These are chat archives for ThoughtWorksInc/Binding.scala

25th
May 2016
Anthony Homan
@anthonyhoman
May 25 2016 05:03
I decided I want to dynamically update my <style> element in my document <head> element
Anthony Homan
@anthonyhoman
May 25 2016 05:09
However, I can't find a clean way to set up the binding. My ScalaCSS code returns a <style> element filled in with all of my styles, but I can't call dom.render on the document.head as it will replace the other content in my <head> element (like <title> <link>, etc.)
So I tried coming up with some sort of BindingSeq[Node] that would contain the original static content of my <head> element plus the dynamically updating <style> element, but I can't find the right syntax
I can get a Binding[List[Node]], but I can't find a way to create my own BindingSeq[Node] from a list
杨博 (Yang Bo)
@Atry
May 25 2016 05:12
val list = Seq(1, 2, 3)
val bs: BindingSeq[Int] = Constants(list: _*)
@anthonyhoman: Try Constants
Anthony Homan
@anthonyhoman
May 25 2016 06:07
Hmm, still can't get it...my problem seems to be something to do with this:
If I create a BindingSeq[Node] as follows, and render it into document.head, it works as expected:
@dom def head = {
      <title>My Title</title>
      <link>Some Link</link>
    }
    dom.render(document.head, head)
But if I try to do an equivalent @dom method using previously cloned dom elements captured in Constants, it doesn't work...only the second element is added to <head>...the first disappears
This message was deleted
val titleElement = Constant(document.head.children.item(0).cloneNode(true))
    val linkElement = Constant(document.head.children.item(1).cloneNode(true))
    @dom def head = {
      { titleElement.each }
      { linkElement.each }
    }
    dom.render(document.head, head)
(ignore the hard coding..it's just for test purposes)
Note though that if I put those titleElement and linkElement elements within a <div> (again, only for test, wouldn't want to put a <div> in <head>), then both elements render properly
val titleElement = Constant(document.head.children.item(0).cloneNode(true))
    val linkElement = Constant(document.head.children.item(1).cloneNode(true))
    @dom def head = {
      <div>
      { titleElement.each }
      { linkElement.each }
      </div>
    }
    dom.render(document.head, head)
Anthony Homan
@anthonyhoman
May 25 2016 06:14
I need to have some sibling elements like that in a @dom method, as ultimately I want to add title, link and style (all siblings) to my <head> element
The only other way would be to add a Binding[Node] to an existing BindingSeq[Node]...is there a way to add the element to the seq? Or a way to combine two BindingSeq's?
杨博 (Yang Bo)
@Atry
May 25 2016 06:21
@dom def headElements = Constants(titleElement.each, linkElement.each)
杨博 (Yang Bo)
@Atry
May 25 2016 06:32
Or you can render the text node only:
@dom def styleTextContent: Binding[Text] = {
  document.createTextNode(???)
}

def main() = {
  dom.render(document.getElementsByTagName("style").items(0), styleTextContent)
}
Anthony Homan
@anthonyhoman
May 25 2016 06:51
Thanks very much...I get it now...I had to get my head around what I was really trying to accomplish and your tips got me there
I ended up going with this...I may make some tweaks later:
val headContents = document.head.children
    val staticList = (0 to headContents.length-1).map(headContents.item(_).cloneNode(true))
    val headElements = Vars(staticList: _*)

    @dom def head = {
      headElements.get += Router.containerStyles.each
      headElements
    }

    dom.render(document.head, head)
杨博 (Yang Bo)
@Atry
May 25 2016 06:55
Don't change a Vars in a @dom method, because a @dom method may be executed multiple times whenever its dependency changes
In your case, every time your Router.containerStyles changes, one more style instance will be added to headElements
I suggest you use Constants instead
    @dom def head = {
      val headContents = staticList :+ Router.containerStyles.each
      Constants(headContents: _*)
    }
杨博 (Yang Bo)
@Atry
May 25 2016 07:01
So that every time your Router.containerStyles changes, a new Constants will be created
Anthony Homan
@anthonyhoman
May 25 2016 07:06
Got it. I wasn't actually seeing a new style element added with each Router change in the previous code, but I'm changing it to use the Constants approach instead