Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Dec 13 21:20
    scala-steward opened #233
  • Dec 12 02:52

    Atry on master

    Update scalafmt-core to 2.3.2 Merge pull request #230 from sc… (compare)

  • Dec 12 02:52
    Atry closed #230
  • Dec 12 02:50
    scala-steward opened #232
  • Dec 12 02:48
    Atry closed #218
  • Dec 12 02:47
    scala-steward opened #231
  • Dec 12 02:47
    scala-steward opened #230
  • Dec 12 02:47
    scala-steward opened #229
  • Dec 12 02:46
    scala-steward opened #228
  • Dec 12 02:46
    scala-steward opened #227
  • Dec 12 02:46
    scala-steward opened #226
  • Dec 07 10:20
    Atry commented #175
  • Dec 07 10:02
    adrobisch commented #175
  • Dec 01 21:52
    Atry commented #175
  • Dec 01 12:39
    adrobisch commented #175
  • Nov 24 09:02
    adrobisch commented #175
  • Nov 24 05:37
    Atry commented #175
  • Nov 24 03:38
    Atry commented #175
  • Nov 23 21:44
    adrobisch commented #175
  • Nov 23 21:44
    adrobisch commented #175
杨博 (Yang Bo)
@Atry
:smile:
Basim Khajwal
@basimkhajwal

Hi, could someone point out what the cause of this error is in the following import com.thoughtworks.binding.Binding.{ Var, Vars }
import com.thoughtworks.binding.dom
import org.scalajs.dom.document

case class Model(name: String, contents: Vars[Double])

@dom
def render = {

val models = Vars(
Model("A Model", VarsDouble)
)

<div>
{
for (model <- models) yield {
<h3>{model.name}</h3>
<ul>
{
for (i <- model.contents) yield {
<li>{i.toString}</li>
}
}
</ul>
}
}
</div>
}

dom.render(document.body, render)

Sorry, forgot to format

The following code is what I'm trying to achieve in my own project (with a more complicated interface but the same error is what I am finding difficult to overcome).

import com.thoughtworks.binding.Binding.{ Var, Vars }
import com.thoughtworks.binding.dom
import org.scalajs.dom.document

case class Model(name: String, contents: Vars[Double])

@dom
def render = {

  val models = Vars(
    Model("A Model", Vars[Double](1,2,3))
  )

  <div>
    {
      for (model <- models) yield {
        <h3>{model.name}</h3>
        <ul>
        {
          for (i <- model.contents) yield {
            <li>{i.toString}</li>
          }
        }
        </ul>
      }
    }
  </div>
}

dom.render(document.body, render)

Running this (https://scalafiddle.io/sf/9eib3hm/0) gives the following error:

ScalaFiddle.scala:16: error: overloaded method value domBindingSeq with alternatives:
  ( text: String )binding.this.Binding.Constants[raw.this.Text] 
    ( node: raw.this.Node )binding.this.Binding.Constants[raw.this.Node] 
      ( seq: Seq[raw.this.Node] )binding.this.Binding.Constants[raw.this.Node] 
        ( bindingSeq: .this.com.thoughtworks.binding.Binding.BindingSeq[raw.this.Node] ).this.com.thoughtworks.binding.Binding.BindingSeq[raw.this.Node]
         cannot be applied to (.this.com.thoughtworks.binding.Binding.BindingSeq[.this.com.thoughtworks.binding.Binding.BindingSeq[raw.this.Node]])
    for (model <- models) yield {
                           ^
    }

Any help would be appreciated

Kahli Burke
@kahliburke
But in general the issue with using for/yield is that it turns into a map operation, when you really want a flatMap for what you're doing. So an alternative way would be to do:
models flatMap { model =>
        <h3>
          {model.name}
        </h3>
        <ul>
          {for (i <- model.contents) yield {
          <li>
            {i.toString}
          </li>
        }}
        </ul>
      }
This is only an issue when you're returning a sequence of xml elements from each element in a Vars or some other collection.
Basim Khajwal
@basimkhajwal
@kahliburke Thanks a lot, I didn't realise the for comprehension was actually using a map operation. In my mind I thought that if it worked for a regular Binding it would also work for a BindingSeq.
Kahli Burke
@kahliburke
@basimkhajwal In scala a for comprehension is syntactic sugar for chaining flatMap, map -> https://docs.scala-lang.org/tutorials/FAQ/yield.html#translating-for-comprehensions
Kahli Burke
@kahliburke
@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
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
Yes, that's clear about.value causing side effects. But doing Binding { someVar.value = someBInding.bind}.watch would be ok?
杨博 (Yang Bo)
@Atry
It's very dangerous. Don't do that.
Kahli Burke
@kahliburke
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
That may create circular dependencies, and may cause some reentry bugs in Binding.scala's internal implementation.
Kahli Burke
@kahliburke
Yeah that's what I was concerned about too.. One option seemed to put Var.value = inside a Future block
杨博 (Yang Bo)
@Atry

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
Are there plans to support scala native?
杨博 (Yang Bo)
@Atry

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
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
It's better to avoid watch...
Kahli Burke
@kahliburke
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
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
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
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
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
Creating a Future or a timer is also side effect. Don't do it in Binding block.
Kahli Burke
@kahliburke
Danger of reentry would be missing some change propagation?
杨博 (Yang Bo)
@Atry
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
Still, MountPoint is an utility to trigger external side effect, not an approach to change Vars.
Kahli Burke
@kahliburke
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
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
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
You can create a Route.Href, similar to the existing Route.Hash.
Kahli Burke
@kahliburke
I have a location based router that watches the href, which seems to work properly
杨博 (Yang Bo)
@Atry
For create generic components, have you tried to add an intermediate Binding that merges the internal Var and external changes together?
Kahli Burke
@kahliburke
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.