Skip to content

Enables async usage in LiveComponent's update_many function

License

Notifications You must be signed in to change notification settings

sezaru/live_bulk_async

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LiveBulkAsync

Hex Hexdocs

LiveBulkAsync is a small library that extends LiveView's async support to work with LiveComponent's update_many function.

Installation

First add LiveBulkAsync to your list of dependencies in mix.exs:

def deps do
  [
    {:live_bulk_async, "~> 0.1.0"}
  ]
end

Now you can directly add support for it in a specific component:

defmodule MyComponent do
  use Phoenix.LiveComponent

  # Add this
  import LiveBulkAsync
  
  ...
end

Or you can enable it in all your components by adding it to your Web module live_component function:

def live_component do
  quote do
    ...
    
    # Add this
    import LiveBulkAsync
  end
end

Usage

Now inside your component update_many function, you can use it like this for start_many_async:

defmodule MyComponent do
  @moduledoc false

  use Phoenix.LiveComponent

  def update_many(assigns_and_sockets) do
    assigns_and_sockets
    |> Enum.map(fn {assigns, socket} ->
      socket |> assign(assigns) |> assign(loading?: true)
    end)
    |> start_many_async(:content, &load/0)
  end

  def handle_async(:content, {:ok, content}, socket) do
    {:noreply, assign(socket, loading?: false, content: content)}
  end

  def handle_async(:content, {:exit, reason}, socket) do
    {:noreply, socket}
  end

  def render(assigns) do
    ~H"""
    <div id={@id}>
      <div :if={@loading?}>loading...</div>
      <div :if={not @loading?}>{@content}</div>
    </div>
    """
  end

  defp load! do
    # Load something here
    ["content 1", "content 2"]
  end
end

And like this for assing_many_async:

defmodule MyComponent do
  @moduledoc false

  use Phoenix.LiveComponent

  def update_many(assigns_and_sockets) do
    assigns_and_sockets
    |> Enum.map(fn {assigns, socket} ->
      socket |> assign(assigns) |> assign(loading?: true)
    end)
    |> assign_many_async(:content, fn -> load!() end)
  end

  def render(assigns) do
    ~H"""
    <div id={@id}>
      <.async_result :let={content} assign={@content}>
      <:loading>Loading...</:loading>
      <:failed :let={reason}><pre>{inspect(reason)}</pre></:failed>
        <div>{content}</div>
      </.async_result>
    </div>
    """
  end

  defp load! do
    # Load something here
    {:ok, %{content: ["content 1", "content 2"]}}
  end
end

Cancel running task

You can also cancel an already running task using cancel_many_async, just keep in mind that calling it will cancel the task for all the components that are using it, not only the one you called it from.

You can cancel a task directly from the update_many call like this:

def update_many(assigns_and_sockets) do
    assigns_and_sockets
    |> Enum.map(fn {assigns, socket} -> socket end)
    |> cancel_many_async(:content)
end

Or from any other callback inside the component that has access to the socket:

def handle_event("cancel_load", _params, socket) do
  socket = cancel_many_async(socket, :content)

  {:noreply, socket}
end

About

Enables async usage in LiveComponent's update_many function

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages