artem

artem

How to evaluate a LiveBook cell with a value **asynchronously** set in the previous cell

Hi All

Context
I am creating a small DB analysis tool in LiveBook to explore what we have in our job matching service. Conceptually this is just several relatively simple cells:

  1. Select a job opening
  2. Select an applicant
  3. Display something about applicant

Choose in the previous cell, update in the next cell helps
People at Select something in one LiveBook cell, update list in another cell - #3 by hugobarauna helped me to figure how to use Kino.listen so that “Select an applicant” set was able to react to choices done in the “Select a job opening” step and show the applicant list only for the selected opening.

It works very well except for the first render of the “Select an applicant step”

The problem
By the moment of the very first render of “Select an applicant step”, job opening selector could be clicked multiple times already and I wail to figure how to pass the current value further (except via ssome external storage such :ets , but that sounds like an ugly overkill).

If that was a LiveView, I would just update process assigns from async callback.
What would be the way to make it work in LiveBook? Is there some sort of “current book context” that could be accessed and updated somehow?

Here’s code of what I want to achieve in a very simplified way:

First cell:

# First cell

button = Kino.Control.button("Click")
counter = 0

Kino.listen(button, fn _event ->
  IO.puts("button clicked, counter is #{counter}")

  # Obviously it won't work as it just createa a local variable,
  # it can't update the earlier defined one
  counter = counter + 1
end)

button

Second cell:

# Second cell should be able to set current counter value somehow
IO.puts("Counter as set by the moment of this cell evaluation:#{counter}")

Kino.listen(button, fn _event ->
  IO.puts("Do something with the current counter of #{counter}, maybe increase it as well")
end)

Most Liked

jonatanklosko

jonatanklosko

Creator of Livebook

There are two paths you can take to write an app:

  1. Separate cells, relying on Kino.Input.read and automatic cell reevaluation. Whenever the input value changes, the dependent cell reevaluates. The benefit in your case is that while a cell is evaluating, it doesn’t matter how many times you change the select value, the next time the cell reevaluates it will just get the latest one.

  2. Using forms and events. When the form is dynamic, you basically want a GenServer with state that manages form events and renders UI into the frame. The idea with the new Kino.Screen abstraction is to make this workflow easier. Since mentioned Agent and shared state, using a single process is a more natural abstraction in this case. This also implies writing pretty much everything in a single cell, which I agree diverges from how you would write a typical notebook, but it is somewhat inherent for a stateful, event-driven app.

From a more technical perspective, the core principle in Livebook notebook evaluation is reproducability. Reading input values and reevaluating cells fits into this model (where inputs are conceptually similar to variables assigned via UI). On the other hand, when we think about events such as button clicks and form submissions, we shift to a different paradigm.

Both 1. and 2. have their use cases. One of the key differences is that with 1. the inputs are shared across everybody entering the page, while with 2. we can build a single app that handles multiple users, and provides each of them with separate interactions, but can also make the experience shared (e.g. a chat).

Ideally we would he a single way of doing things, but so far the consensus has been that each of them has a place.

Where Next?

Popular in Questions Top

logicmason
Hi there, I'm working through my first release with elixir/phoenix. I've built a release with distillery and found that it crashes when I...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> someth...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New

Other popular topics Top

belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
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
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
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
peerreynders
Manning 2016 Halloween weekend sale via Deal of the Day Friday, October 28 - Half off all MEAPs - code WM102816LT Saturday, October 29 ...
326 29600 154
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
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
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
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New

We're in Beta

About us Mission Statement