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:
- Select a job opening
- Select an applicant
- 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
There are two paths you can take to write an app:
-
Separate cells, relying on
Kino.Input.readand 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. -
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.Screenabstraction is to make this workflow easier. Since mentionedAgentand 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.







