fceruti

fceruti

A tiny macro to clean LiveView code

Sup ppl, I just wanted to share a little macro I created to simplify LiveView code. It allows you to convert

socket.assings.variable

into

~a|variable|

For instance here’s a function from Chris McCord’s live_trek

  def handle_event("delete", %{"id" => id}, socket) do
    todo = Todos.get_todo!(socket.assigns.scope, id)
    {:ok, _} = Todos.delete_todo(socket.assigns.scope, todo)

    {:noreply, socket}
  end

Would be

  def handle_event("delete", %{"id" => id}, socket) do
    todo = Todos.get_todo!(~a|scope|, id)
    {:ok, _} = Todos.delete_todo(~a|scope|, todo)

    {:noreply, socket}
  end

Necessary? Not really.

But I thought it looks much better, specially when you have lot’s of socket.assigns and want to reduce verbosit, avoid unpacking assigns and reduce formatter line breaks.

Here’s v0.1

  defmacro sigil_a(expr, _modifiers) do
    socket = Macro.var(:socket, nil)

    quote do
      Map.get(unquote(socket).assigns, String.to_existing_atom(unquote(expr)))
    end
  end

And here’s a vim command to search and replace:

:%s/socket\.assigns\.\([a-zA-Z0-9_]*\)/\~a|\1|

Most Liked

zachallaun

zachallaun

If you wanted to be really evil, you could overload the @ operator if the caller environment contains socket :smiling_imp:

defmodule Evil do
  defmacro __using__(_) do
    quote do
      import Kernel, except: [@: 1]
      import Evil
    end
  end

  import Kernel, except: [@: 1]

  defmacro @name do
    var = Macro.var(:socket, nil)

    if assigns_call?(__CALLER__, name) do
      {name, _, _} = name
      quote(do: Map.fetch!(unquote(var).assigns, unquote(name)))
    else
      quote(do: Kernel.@(unquote(name)))
    end
  end

  defp assigns_call?(env, {name, _, nil}) when is_atom(name) do
    Macro.Env.has_var?(env, {:socket, nil})
  end

  defp assigns_call?(_, _), do: false
end

defmodule Hmm do
  use Evil

  @okay :foo

  def maybe(socket) do
    @okay
  end

  def wow do
    @okay
  end
end

dbg(Hmm.maybe(%{assigns: %{okay: :NEAT!}}))
dbg(Hmm.wow())

(don’t do this)

tfwright

tfwright

Nice idea. Curious, why Map.get rather than fetch? I think the behavior being replaced raises if the expected key is missing, whereas this will return nil I think

sodapopcan

sodapopcan

Innnnnteresting. I was trying to figure out how to do something like this and couldn’t figure it out. I was trying to use var!/2 for this to no avail. I never understood that you can check the caller env.

I was looking to create a single guard that would work on both socket and assigns. I have a lot of single module CRUD LiveViews so I wanted something like:

def handle_event("update", %{"user" => user_params}, socket) when in_action([:edit]) do
  #...
end

def render(assigns) when in_action([:edit]) do
  ~H"""
  """
end

This would check whichever existed of socket.assigns.live_action or assigns.live_action was in [:edit].

Even though I don’t think that is particularly evil (that is, what I wanted to do—what you’re suggesting is absolutely pure evil :see_no_evil_monkey: :sweat_smile:) , I ultimately decided I’d rather not do anything out the ordinary like this so I never bothered to seek help figuring it out, but it’s nice to know how it could be done, so thanks!

(that is, if that would even solve the problem… I haven’t actually tried, just responded immediately, lol, but still informative for me)

Where Next?

Popular in Guides/Tuts Top

Logan
Here is an example of a Mix application that utilizes Cowboy to handle websocket connections. If anyone has an idea about making this wor...
New
stryrckt
I’m excited about the new LiveComponents feature in LiveView, but I haven’t seen much written on it, so I decided to write a couple of ar...
New
kuon
I have a page with a large state that is loaded from DB, let’s call that “data”. I have a root live view that load “data” on mount and r...
New
fmcgeough
pipe into case? I use that fairly frequently…unless I’m misunderstanding what you’re wanting…could be.. its still very early… str = "Hel...
New
sergio
Hey there, we’re going to walk through deploying a Phoenix app to a DigitalOcean droplet, manually - no tools no nothing. Just straight u...
New
crockwave
To integrate dropdown menus in a Phoenix Liveview app, you can use a combination of js, Hooks, CSS and your .leex and .ex code. You can...
New
eclark
I’ve been working on a phoenix project lately and I wanted to use the latest versions of everything. Webpack 5 had some breaking changes ...
New
dkuku
I Created a blog post about setting up svelte with phoenix. I found it a bit tricky and the only blog post I found was written using som...
New
mhanberg
Hi! I recently finished adding authentication to my Phoenix API, so I wanted to share what I learned. I haven’t created authentication f...
New
nietaki
Just a quick heads up: There seems to be a bug in Erlang/OTP 21.3, which can cause some errors when making http requests. If you’re using...
New

Other popular topics Top

TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42158 114
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement