Closed juweoncom closed 3 years ago
This is going to be a no-op, I think
inputStream.foreach(_ => adder)
inputStream.foreach(adder) // !!! Compile Error
Airstream documentation often assumes that you have an implicit Owner
in scope to reduce boilerplate (but it does explain that the foreach
method needs one).
inputStream.foreach(_ => adder)
As Iurii said, this is a noop because the value you return inside the foreach
callback is discarded. It needs to be inputStream.foreach(adder.onNext)
, or better yet inputStream.addObserver(adder)
.
If you're actually using Laminar, inputStream --> adder
inside an element will work just fine. But on its own, this expression returns a Laminar Modifier which will not create a subscription until it's added to a Laminar element that is mounted. inContext
does not change that. So if you are not actually using Laminar, you need to provide your own instances of Owner
instead of trying to use Laminar instances. You can read more about how to create custom owners in the Ownership docs section.
Thank you for your good explanations! Yes, somehow I understood from documentation that it has something to do with ownership.
Nevertheless, even with implicit Owner
in place the snippet of the documentation does not compile and this was confusing.
val v = Var(List(1, 2, 3))
val adder = v.updater[Int]((currValue, nextInput) => currValue :+ nextInput)
adder.onNext(4)
v.now() // List(1, 2, 3, 4)
val inputStream: EventStream[Int] = ???
implicit val owner: Owner = ??? // required implicit owner
inputStream.foreach(adder) // Compile error!!!
On the other hand it was confusing that inputStream --> adder
works inside inContext
but not outside. But no implicit parameter for the owner was required. So I understood that there has(!) to be some side effect that makes it work. But that mechanism was hidden to me. Somehow I knew from documentation that this has something to do ownership but I could not grasp it.
Some clear words about that mechanism in the documentation would help.
PS: I appreciate the philosophy of Airstream and Laminar very much and would like more people to use it. But perhaps some people had the same misunderstanding as me and put it aside.
Perhaps the pattern I'm using is illuminating:
val $varA = Var("Text")
// this doesn't work here
// val $streamA: EventStream[String] = ???
// $streamA --> $varA
div (
inContext { _ =>
// here it works producing a comment in UI
val $streamA: EventStream[String] = ???
$streamA --> $varA
},
children <-- $varA.signal.map(??? /*render*/)
)
Do you have a better idea?
inputStream.foreach(adder) // Compile error!!!
Ah, I missed it the first time. adder
is an Observer
, not a Function
, so you need to use addObserver
instead of foreach
:
inputStream.addObserver(adder) // An implicit owner is still required.
On a side note, if you're facing a compiler error that you have a question about, it's easier for me to help if you tell me what the compiler actually says. There can be several reasons why something might not compile.
On the other hand it was confusing that
inputStream --> adder
works insideinContext
but not outside
That's just not the case. Wrapping into inContext
makes no difference. In your latest code snippet (it does help, thanks), the important difference between "this doesn't work here" and "here it works" is not inContext
, it's that you put $streamA --> $varA
inside of the div. This will work just as well:
val $streamA: EventStream[String] = ???
div(
$streamA --> $varA,
children <-- $varA.signal.map(??? /*render*/)
)
In Laminar terms, $streamA --> $varA
is a Modifier
. If it's not inside an element like div()
, it's not gonna do anything. That's expected. Even if it's inside a div, it will only work if that div is mounted into the DOM. This is all explained in Laminar docs, for example, from the Binding observables section:
By now you must have realized that --> and <-- methods are the main syntax to connect / bind / subscribe observables to observers in Laminar.
To be more precise, such methods always return a Modifier that needs to be applied to an element. And when it is applied, a dynamic subscription is created such that it activates when the element is mounted, and deactivates when the element gets unmounted.
And then it goes on to explain how the ownership lifecycle activates and deactivates these subscriptions.
There's also a video which gives a broad introduction to Laminar concepts, make sure you've watched it if you haven't yet. It does talk about modifiers, and explains several code examples.
If you have more how-to / why questions, our gitter is a better channel for that, more people watching over that.
Observers Feeding into Var
documentation seems to be wrong or at least be confusing to me.This doesn't compile:
Whereas this compiles:
But still
inputStream --> adder // Laminar syntax
seems to have no effect. I assume because no owner is provided. I had to wrap it in something like: