# `Masu.Live`
[🔗](https://github.com/hattoriai/masu/blob/v0.1.0/lib/masu/live.ex#L1)

Live rows: a grid that follows a PubSub topic, and shows the rows that
change on it as they change.

    <.data_grid id="orders" source={Order} repo={Repo} live={{MyApp.PubSub, "orders"}}>

Where the rows change, broadcast them:

    {:ok, order} = Repo.update(changeset)
    Masu.Live.broadcast_upsert(MyApp.PubSub, "orders", order)

    Repo.delete!(order)
    Masu.Live.broadcast_delete(MyApp.PubSub, "orders", order)

The grid takes the change into the rows of its query, with the person's
order, filters and search, changes its count, and the browser shows the
new rows in the place the person reads, each changed row with a short
highlight. A grid of an Ecto source asks its query again; a grid of a
list puts the row in the list (by its id), or takes it out.

Changes that come together, as from a batch of updates, make one new
set of rows: the grid takes every change that waits in the LiveView's
mailbox at once.

## The hook

The LiveView process subscribes to the topic, and its `handle_info`
receives the changes: this `on_mount` hook takes them, so the LiveView
needs no clause of its own. Add it to the LiveView, or to its
`live_session`:

    on_mount Masu.Live

    live_session :default, on_mount: [Masu.Live] do

A grid with `live` in a LiveView without the hook raises, saying so.

## A list and its LiveView

A grid of a list keeps the changes in its own copy of the list. The
LiveView's assign does not change: give the grid new `rows` (which
replace its copy) or broadcast changes, not both.

# `change`

```elixir
@type change() :: {:upsert, term()} | {:delete, term()}
```

A change to the rows of a topic.

# `broadcast_delete`

```elixir
@spec broadcast_delete(atom(), String.t(), term()) :: :ok | {:error, term()}
```

Broadcasts a row that was deleted, given as the row or its id: a grid
that follows the topic takes it out.

# `broadcast_upsert`

```elixir
@spec broadcast_upsert(atom(), String.t(), term()) :: :ok | {:error, term()}
```

Broadcasts a row that was inserted or changed: a grid that follows the
topic shows it, in the place of its query.

# `export`

```elixir
@spec export(String.t()) :: Masu.Export.t()
```

The export of the grid `grid` of this LiveView (`Masu.Export`): its
rows as they are now (the person's order, filters and search), with
the columns that show. Call it in the LiveView; write it anywhere.

# `selected`

```elixir
@spec selected(String.t()) :: {:ids, [term()]} | {:query, term()}
```

The rows selected in the grid `grid` of this LiveView (`selectable`):
`{:ids, ids}`, or, when the person selected every row of the query,
`{:query, query}` for an Ecto source (an `Ecto.Query` of the rows, with
the person's filters and search, less the rows they took out of it) and
`{:ids, ids}` of every such row for a list.

    def handle_event("archive", _params, socket) do
      case Masu.Live.selected("orders") do
        {:ids, ids} -> Orders.archive(ids)
        {:query, query} -> Repo.update_all(query, set: [archived: true])
      end

      {:noreply, socket}
    end

---

*Consult [api-reference.md](api-reference.md) for complete listing*
