These are chat archives for ThoughtWorksInc/Binding.scala

7th
Dec 2017
Kahli Burke
@kahliburke
Dec 07 2017 18:06
@Atry I'm wondering if you can clarify use of Var.value given the comment * @note This method must not be invoked inside a @dom method body.?
Is that purely about the @dom macro or does that extend to setting Var.value inside a Binding{ .. } block?
杨博 (Yang Bo)
@Atry
Dec 07 2017 18:09
A @dom function is just a HTML template, which should be pure without any side effects, so doBinding blocks.
Both .value and .value_= are side effects.
Kahli Burke
@kahliburke
Dec 07 2017 18:10
Yes, that's clear about.value causing side effects. But doing Binding { someVar.value = someBInding.bind}.watch would be ok?
杨博 (Yang Bo)
@Atry
Dec 07 2017 18:11
It's very dangerous. Don't do that.
Kahli Burke
@kahliburke
Dec 07 2017 18:11
Haha
Ok, I'm trying to figure out how to accomplish setting of a Var, say related to a user's choice in UI from some other Binding value that can sometimes change
杨博 (Yang Bo)
@Atry
Dec 07 2017 18:14
That may create circular dependencies, and may cause some reentry bugs in Binding.scala's internal implementation.
Kahli Burke
@kahliburke
Dec 07 2017 18:15
Yeah that's what I was concerned about too.. One option seemed to put Var.value = inside a Future block
杨博 (Yang Bo)
@Atry
Dec 07 2017 18:15

Ok, I'm trying to figure out how to accomplish setting of a Var, say related to a user's choice in UI from some other Binding value that can sometimes change

You can try to not use Var for that case. Use Binding block instead.

Lorenzo Gabriele
@lolgab
Dec 07 2017 18:16
Are there plans to support scala native?
杨博 (Yang Bo)
@Atry
Dec 07 2017 18:17

Yeah that's what I was concerned about too.. One option seemed to put Var.value = inside a Future block

There is a FutureBinding for remote data. You can use it instead of Vars.

@lolgab It would be not very hard to support scala-native. PR is welcomed.
Kahli Burke
@kahliburke
Dec 07 2017 18:18
This isn't for Future data from a call, the Var represents user state in an input element, but some other event happens in a different UI element and I want to respond to that change (via otherComp.bindingProperty.bind) and change the user's selection.
The idea was to use Binding { val store = binding.bind; Future { var.value = store} }.watch to break out of Binding context
杨博 (Yang Bo)
@Atry
Dec 07 2017 18:20
It's better to avoid watch...
Kahli Burke
@kahliburke
Dec 07 2017 18:23
Yeah it's not my go to approach but I'm trying to figure out how to write a generic input component with Var for its internal state in a way that it can also respond to some external change... seems tricky to do it without var, and how else do I hook up external.bind -> inputelem.value? The other thing I thought of was to completely recreate my input component in response to external change but I was trying to avoid that.
杨博 (Yang Bo)
@Atry
Dec 07 2017 18:27
You can create another Binding that merges internal Var and external changes together.
Thinking about the dependency graph. A Var is always the source of the onchange event, not a intermediate node.
Kahli Burke
@kahliburke
Dec 07 2017 18:30
Yes the graph makes sense. So my takeaway is that the warning about @dom applies to Binding {} as well, correct? Is the issue around circularity causing 'cycles' where dirty values cause other things to become dirty and we miss rendering properties (like digest cycles in the Angular world), or circularity causing stack overflow or other endless loop problems?
杨博 (Yang Bo)
@Atry
Dec 07 2017 18:32
It will never cause stack overflow in Binding.scala. But it will cause some reentry, which Binding.scala did not mean to support.
Kahli Burke
@kahliburke
Dec 07 2017 18:32
The idea in putting value set into a Future was to get out of the graph and schedule a new change event to occur in the future.
杨博 (Yang Bo)
@Atry
Dec 07 2017 18:34
Creating a Future or a timer is also side effect. Don't do it in Binding block.
Kahli Burke
@kahliburke
Dec 07 2017 18:34
Danger of reentry would be missing some change propagation?
杨博 (Yang Bo)
@Atry
Dec 07 2017 18:34
If you really want to trigger side effect, you can use MountPoint.
MountPoint has more control to life cycle of event handlers than Binding blocks.
杨博 (Yang Bo)
@Atry
Dec 07 2017 18:40
Still, MountPoint is an utility to trigger external side effect, not an approach to change Vars.
Kahli Burke
@kahliburke
Dec 07 2017 18:40
Yes, I have read this and it makes sense for that use case, it's not immediately clear to me how I'd apply it in this situation.
杨博 (Yang Bo)
@Atry
Dec 07 2017 18:41
Though it is acceptable to use MountPoint to create a timer to change Vars.
You can create animations in that way.
If you want to change Var directly, then it's not your solution.
Kahli Burke
@kahliburke
Dec 07 2017 18:50
Thanks for the information, I'll need to experiment a little bit to find a path I think. I think the main issue is around writing generic components (like a self contained class representing a select input) that can respond to both direct user input on that control, but also from changes that propagate from other controls in the system.
In this case, I actually want to respond to changes in the window.location history
Which propagate down through other structures, like a router
杨博 (Yang Bo)
@Atry
Dec 07 2017 18:52
You can create a Route.Href, similar to the existing Route.Hash.
Kahli Burke
@kahliburke
Dec 07 2017 18:57
I have a location based router that watches the href, which seems to work properly
杨博 (Yang Bo)
@Atry
Dec 07 2017 19:00
For create generic components, have you tried to add an intermediate Binding that merges the internal Var and external changes together?
Kahli Burke
@kahliburke
Dec 07 2017 19:06
I haven't, it may be a good approach but I'll have to spend some time investigating how to incorporate that, as right now the select input is nicely encapsulated, it renders out its DOM based on its internal structure, so to modify it to also accept some additional Binding that controls it for some less common cases seems dirty. What I have working now is that when the location changes, the select box object itself gets recreated, this instantiates a new Var but doesn't manipulate an existing one.
杨博 (Yang Bo)
@Atry
Dec 07 2017 19:08
Your approach looks good to me.
Kahli Burke
@kahliburke
Dec 07 2017 19:10
Ok, one thing that I might have right! :)
杨博 (Yang Bo)
@Atry
Dec 07 2017 19:13
If what you want to recreate is just the Var, you can avoid recreating the HTML elements by use a Binding[Var[State]]as your internal state holder inside YourComponent, instead of Binding[YourComponent].
Kahli Burke
@kahliburke
Dec 07 2017 19:19
Why the double wrapping of Var in Binding?
杨博 (Yang Bo)
@Atry
Dec 07 2017 19:27
val bvs: Binding[Var[State]] = Binding {
  Var(externalState.bind)
}
Also your xxxHandler should change to Binding[Event => Unit] types as well.
杨博 (Yang Bo)
@Atry
Dec 07 2017 19:38
def changeHandler = Binding {
  val vs = bvs.bind;
  { event: Event =>
    vs.value = event.currentTarget.asInstanceOf[Input].value
  }
}

@dom def renderComponent = {
  <input value={bvs.bind.bind} onchange={changeHandler.bind} />
}