cd-slash

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

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

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

Where Next?

Popular in Questions Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
LegitStack
I’m hoping you guys can give me some general advice and perhaps code examples if you’re feeling up to it. I’m very interested in Elixir,...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
fireproofsocks
I’m working on defining a simple Ecto schema for a table (in PostGres), but I don’t see where I can define a column as NOT NULL. Conside...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
mathew4509
I have a list say x = ["23gh", "56kh", "97mh"] I would like to pass each element to Val in each iteration. Say, in iteration 1 -------...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New

Other popular topics Top

yurko
Here are few pieces of (common) Linux knowledge that we use for reasonably small one server apps. We use Ubuntu but this should work for ...
New
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New

We're in Beta

About us Mission Statement