cd-slash
Case to bind variable with assigns
I have a really simple component that places a rectangle over the corner of an image to leave a cutout. As written below it works as intended:
attr :top, :boolean, default: false
attr :bottom, :boolean, default: false
attr :left, :boolean, default: false
attr :right, :boolean, default: false
def corner_cutout(assigns) do
assigns =
assign(assigns,
rotation:
case {assigns.top, assigns.bottom, assigns.left, assigns.right} do
{true, false, true, false} -> 30
{true, false, false, true} -> 330
{false, true, true, false} -> 30
{false, true, false, true} -> 330
end
)
~H"""
<div class={"w-32 h-32 bg-white transform rotate-[#{@rotation}deg]"}></div>
"""
end
and this allows me to really cleanly use the cutout in another component:
~H"""
<.corner_cutout top left />
"""
What bugs me though is the case statement, where it’s quite hard to read what is matching for each of the case clauses since it’s relying on positional arguments.
I tried re-writing by passing in assigns to the case statement so that it would match on something like {assigns.top, assigns.left} -> 30 and multiple variations of this, but always get the error cannot invoke remote function assigns.top/0 inside a match.
Is there a way to re-write this so it’s more readable and I don’t have to match the position of the booleans to know what’s matching?
Marked As Solved
Sorc96
You can match assigns like this:
case assigns do
%{top: true, left: true} -> 30
%{top: true, right: true} -> 330
end
Or you can even type out the ones that should be false to make sure that the input is valid:
case assigns do
%{top: true, bottom: false, left: true, right: false} -> 30
end
Also Liked
al2o3cr
At a minimum, consider extracting the case to a private function:
defp cutout_rotation(assigns) do
case {assigns.top, assigns.bottom, assigns.left, assigns.right} do
{true, false, true, false} -> 30
{true, false, false, true} -> 330
{false, true, true, false} -> 30
{false, true, false, true} -> 330
end
end
Another way to shorten it would be to notice that only 4 of the possible 16 combinations are included in the case, so a cond for just those would be shorter:
defp cutout_rotation(assigns) do
cond do
assigns.top && assigns.left -> 30
assigns.top && assigns.right -> 330
assigns.bottom && assigns.left -> 30
assigns.bottom && assigns.right -> 330
end
end
I’m not normally a huge fan of pattern-matching a bunch of fields, but you could do it if all the assigns. in the previous version seem repetitive:
defp cutout_rotation(%{top: top, left: left, right: right, bottom: bottom}) do
cond do
top && left -> 30
top && right -> 330
bottom && left -> 30
bottom && right -> 330
end
end








