Visualize Easing Animation Curves
easings.net has a handy table for visualizing easing functions for animation curves.
easings.net has a handy table for visualizing easing functions for animation curves.
The delayLongPress
prop on the react native pressable component allows you to specify a delay in milliseconds before the onLongPress
callback prop is executed. Allowing you to control exactly how long a user should press on the element before receiving feedback etc.
You can set the dimensions of the simulator window to be the exact physical size of the simulated device on the xcode IOS simulator.
Window -> Physical Size or Command + 1
In React Native you can use the onLayout
prop along with the nativeEvent's layout to get the dimensions (in pixels) of a rendered component.
const [viewDimensions, setViewDimensions] = useState({height: 0, width: 0})
return (
<View
onLayout={(e) => setViewDimensions(e.nativeEvent.layout)}
/>
)
Now we have an object containging our view's height and width saved as viewDimensions
In React Native, the RefreshControl
component can be placed inside of a scrollview component to handle refreshes. When the user scrolls up, the onRefresh
function will be called where you can handle your refresh/query logic.
You can keep your xcode IOS simulator window on top of all your other windows by selecting Window -> Stay on top
If you want to see the device keyboard while using the Xcode simulator, use ⌘ + K
With Expo's CLI, the command npx expo run:ios
will build and run your application in xcode's IOS simulator. You will need to have Xcode installed in order for the command to work. If you receive an error stating Xcode must be fully installed before you can continue
, you may need to navigate to Xcode's settings and set a version of command line tools under the locations
tab.
File.stat/2
will return data from the path passed to it, including the accessed time atime
and the modified time mtime
.
In a Sentry session replay, you can view if a user rage clicks on an element in your app. A rage click is defined as "a series of rapid clicks on the same unresponsive element".
Similarly, sentry records "Dead" clicks when a user clicks on an element and the page does not visibly respond within 7000ms.
If you're anything like me, you regularly forget if Enum.filter/2
keeps elements that return true or filters them out.
Let existence of Enum.reject/2
be your reminder.
reject/2
does the same thing as filter/2
but discards truthy elements instead of keeping them. I wish that filter/2
was renamed to keep/2
, then the 2 functions would feel more like logical opposites and perhaps more readable.
If you pass the -p
option to mkdir, it will create any necessary parent directories that do not exist yet. In Elixir the File.mkdir_p/1
function will do the same thing!
You can sort an enum by multiple keys at once. For example, If we wanted to sort a list of 'Vehicle' structs by type and model at the same time, we could do this:
vehicle_list = [
%Vehicle{type: "van", model: "Odyssey"},
%Vehicle{type: "truck", model: "Avalanche"},
%Vehicle{type: "van", model: "Pacifica"},
%Vehicle{type: "truck", model: "Bronco"}
]
Enum.sort_by(vehicle_list, &{&1.type, &1.model})
#=>
[
%Vehicle{type: "truck", model: "Avalanche"},
%Vehicle{type: "truck", model: "Bronco"},
%Vehicle{type: "van", model: "Odyssey"},
%Vehicle{type: "van", model: "Pacifica"},
]
sort_by
is first sorting the vehicles by the :type
key and then sorting by the :model
key.
In an Ecto query expression, use distinct: true
to ensure the values returned from your query are distinct.
from(u in User, distinct: true, select: u.first_name)
You can also use distinct with an expression to be more specific
from(u in User,
distinct: last_name,
order_by: [asc: :last_name])
git checkout -
takes you right back to the previously checked out branch.
git stash clear
does exactly what it sounds like!
By declaring @primary_key false
in an Ecto embedded schema, the struct will not require a primary key!
By including redacted: true
when defining a field on an ecto schema, Ecto will redact the field value in a changeset and hide the field when inspecting the schema
When inserting an struct with Ecto.Repo, you can use the on_conflict
option to handle the case of a constraint conflict. The options you can provide include
:nothing
, :replace_all
, {:replace_all_except, fields}
, and {:replace, fields}
If you want to limit the permissible values of a Phoenix Component attribute, you can use the values
keyword list option when you call attr/3
. Here's is an example that restricts which atoms are being passed to the component:
use MyApp.Component
attr :acceptable_color, :atom, values: [:green, :blue]
if you were to pass any atom other than :green
or :blue
to this component, the compiler will warn you.
validate_inclusion/4
allows you to validate that specific data is included in a changeset. One way you could use it is by restricting a field's accepted values like this:
changeset
|> validate_inclusion(:direction, ["left", "right"])
if the value of the :direction field is not "left" or "right" a validation error will be added to the changeset
If you are building an Ecto.Multi transaction and you need to add a function that is not a direct repo operation, you can use Ecto.Multi.Run
and pass a function to it. The function you pass to Ecto.Multi.Run
must return either {:ok, value}
or {:error, value}
in order for the multi operations to continue.
You can change the underline offset spacing with the Tailwind class underline-offset-{width}
If you want to create custom validations with ecto changeset, chances are you are going to need to add errors to the changeset to be shown to the user.
Using add_error/4
allows you to add an error to a changeset.
changeset = change(%BlogPost{}, %{content: "Hello World ...cont"})
add_error(changeset, :content, "Your blog content is too long!")
changeset.errors
[content: {"Your blog content is too long!", []}]
You can convert an Ecto.Changeset back to a schema by using Ecto.Changeset.apply_changes/1
movie_changeset = change(%Movie{title: "Citizen Kane"}, %{director: "Orson Welles"})
#=> This returns an ecto changeset with the new director change
apply_changes(movie_changeset)
#=> %Movie{title: "Citizen Kane", director: "Orson Welles"}
Call recompile
when running iex with mix to recompile the project. This works just like the rails console reload!
command.
In Elixir, you can get the difference between two NaiveDateTimes using the NaiveDateTime.diff/3
function.
The third arg allows you to pass a unit such as :microsecond
, :millisecond
, or any unit returned from System.time_unit. By default, the unit is set to :second
.
NaiveDateTime.diff(~N[2014-10-02 00:29:18], ~N[2014-10-02 00:29:10])
#=> 8
NaiveDateTime.diff(~N[2014-10-04 00:29:18], ~N[2014-10-02 00:29:10], :day)
#=> 2
Interestingly enough :day works as a unit, but not :month, or :year. 🤔
You can use /i
at the end of a regex to match with case insensitivity.
The regex: /hello/i
Will match HELLO
, hello
, and Hello
This is a neat pattern matching trick in elixir, its best explained with a simple example:
invoice_message = "You owe $34"
"You owe " <> dollar_amount = invoice
IO.inspect(dollar_amount)
# => "$34"
With a slightly different situation, It may seem like you could do this:
invoice_message = "You owe 34 dollars"
"You owe " <> dollar_amount <> " dollars"= invoice
IO.inspect(dollar_amount)
# => ** (ArgumentError) the left argument of <> operator inside
# a match should always be a literal binary because its size can't be verified. Got: dollar_amount
But sadly you'll need to use regex to do that because elixir will throw an error.
If you want to gracefully kill all of your tmux sessions/windows/panes in one fell swoop, run tmux kill-server
You can create custom sigils by following the sigil_{character}
definition pattern. Let's make an addition sigil sigil_a
that sums up space separated numbers.
defmodule CustomSigil do
def sigil_a(string, []) do
string
|> String.split(" ")
|> Enum.map(& String.to_integer(&1))
|> Enum.sum()
end
end
# ~a(2 4 6)
#=> 12
# ~a(12 12)
#=> 24
In your test.exs
config change from
config :logger, level: :warning
to
config :logger, level: :debug
to see your app's logs output when running mix test
Use lsof -i :port_number
to find details about a process listening on whichever port you pass.
For example, if you were running a local server on port 4000 and wanted to find the server's PID you could run lsof -i :4000
use ctrl+a
to jump the cursor to the beginning of the line, and ctrl+e
to jump the cursor to the end of the line.
DateTime.truncate(datetime, precision)
Calling this function on a DateTime allows you to change the level of precision from microsecond
, :millisecond
, or :second
.
now = DateTime.utc_now()
# => ~U[2023-10-09 17:52:05.305420Z]
DateTime.truncate(now, :second)
# => ~U[2023-10-09 17:52:39Z]
You can wrap strings and atoms with brackets in elixir to use them as keys in maps
var_key = :name
# This is the syntax for using that variable as a key name
%{[var_key] => "Jack Rosa"}
# => %{name: "Jack Rosa"}
The elixir Kernel module has an interesting function i/1
that returns information about whatever you pass to it.
It will provide the argument's data type, byte size, raw representation, a description, and reference modules
i("hello world")
#=>
# Term
# "hello world"
# Data type
# BitString
# Byte size
# 11
# Description
# This is a string: a UTF-8 encoded binary. It's printed surrounded by
# "double quotes" because all UTF-8 encoded code points in it are printable.
# Raw representation
# <<104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100>>
# Reference modules
# String, :binary
# Implemented protocols
# Collectable, IEx.Info, Inspect, List.Chars, String.Chars
~
in Vim toggles the case of the character under the cursor and then moves the cursor to the next character.
https://realfavicongenerator.net/ can audit your website's favicon's to show which devices and browsers will display your favicon properly.
The site also helps with favicon generation and target resolutions.
You can use Cmd (⌘) + w
in VS Code to close the currently open file.
Elixir has an interesting defined sorting order for its data types. The order is as follows:
number < atom < reference < function < port < pid < tuple < map < list < bitstring
For example:
random_data = [["Hello World"], {:hello, :world}, 16, %{key: "value"}, :atom]
Enum.sort(random_data)
#=> [16, :atom, {:hello, :world}, %{key: "value"}, ["Hello World"]]
Or even
4 < :atom
#=> true
Unix timestamps are a very simple way to compare times in an integer format. They are the total seconds elapsed since January 1st, 1970 UTC (The Unix Epoch).
In elixir, if you want to do some operations on a DateTime
struct, and want to keep things simple, you can convert a DateTime
struct to an integer with to_unix/2
. By default, it will use seconds as the unit.
The *
character can be used as a wildcard to match sequences of unknown characters in the command line.
For example, lets say my elixir project has a few tests that I want to run in a directory: MyProject/tests
. The folder is filled with a bunch of random files, but the ones that i want to run have a similar name, tests/user_views_home
and tests/user_views_show
. We could use a wild card to match on both of these file names and run the tests (assuming there are no other files that match) like this:
mix test MyProject/tests/user_views*
When using ⌘+d
to create multiple cursors in VSCode, each cursor has its own independent clipboard. With each cursor you can copy different text selections and paste them separately. 🤯
By using the wc
command, you can print out word count information to the terminal. By default, if you use the wc
command along with a file path, the command will return 3 values: the line count, word count, and character count of that file.
You can also pipe the wc
command into any other terminal command to receive the word count information about the previous command. For instance, you could use the command ls | wc
to see the word count info for the current directory's file list.
If you want the wc
command to only output either the line count, word count, or char count, you can pass it the following flags: wc -l
for line count, wc -w
for word count, and wc -c
for the char count.
If you want to pull the value of a specific change out of a changeset, you can use fetch_change/2
. Simply pass the function a changeset, and the name of the column where you want to see the change.
changeset = change(%User{}, %{first_name: "John"})
|> fetch_change(:first_name)
# => "John"
Have you ever wanted to pass your own custom function into a guard clause?
Lets start by looking at a super basic guard clause here:
def greater_than_10(num) when num > 10, do: true
def greater_than_10(_), do: false
Let's say we want to get more specific with the operation inside of the when
guard. This is overkill for our situation, but lets say we want the when
to use a custom function of ours instead of a basic operation, but when
guards don't allow you to directly pass functions to them.
Elixir has a fancy macro called defguard
that allows you to define custom guards like functions. Let's change our function up and define a guard that checks if our argument is both a integer and even.
defmodule Guards do
defguard is_even_num(num) when is_integer(value) and rem(value, 2) == 0
end
Let's use that guard in our function
import Guards
def even_num_greater_than_10(num) when is_even_num(num) do
case num > 10 do
true -> true
_ -> false
end
end
Even though this example is a bit overkill, the option to use custom guards is a cool elixir feature.
With Tailwind's accent-{color}
class, you can customize your form's colors. On your input, simply add the class along with the color of your choice like this:
<input type="checkbox" class="accent-red-300" checked>
And the result looks like this! (its an image btw, I'll save you a click)
This works for the accent colors of radio groups as well.
You can use Ctrl+a to jump to the next number and increment. To jump to the next number and decrement, use Ctrl+x.
Jumping to the next number only works on your current line.
If you want to cast changes on a struct's associations, you can use the changeset function cast_assoc/3
. This allows you to make changes to a parent struct and its associations at the same time.
Lets say you have a struct called Artist
and an associated schema called Album
. The schema for the Album
looks something like this:
def module MyApp.Music.Album do
use Ecto.Schema
alias MyApp.Music.Artist
schema "albums" do
field :title, :string
belongs_to :artist, Artist
end
def changeset(artist, params \\ %{}) do
artist
|> cast(params, [:title, :artist_id])
|> validate_required([:title])
end
end
and the schema for artist looks like this:
def module MyApp.Music.Artist do
use Ecto.Schema
alias MyApp.Music.Album
schema "albums" do
field :name, :string
has_many :albums, Album
end
end
Now, if you wanted to build a changeset for the Artist
where you can change the artist's name and the title field on an associated album:
def changeset(artist, params \\ %{}) do
artist
|> cast(params, [:name])
|> cast_assoc(:albums, with: &MyApp.Album.changeset/2)
|> validate_required([:name])
end