How to dynamically build a tree ?

I have some hierarchical data list/file like:
Europe, Germany, Berlin
Europe, Italy, Rome
Africa, Agypt, Cairo
...
Now I want to build a Enyo tree of controls using enyo.node kind.
How can I dynamically add enyo.node instances to build a tree structure from the given data?
In enyo I see there is createComponent() but how can I insert a component at the spot where is needs to be added in the tree?
The resulting tree should appear like a file folder structure.

Comments

  • You can set the addBefore property of a new Node OR you can use Control's insertNodeInParent method (though, I think this one is private).

    Otherwise, put everything in a sorted structure and as you get new entries, re-build the tree from it.
  • @sugardave - thanks for the hints !
    Not sure if I get it to work.
    With addBefore: I can not really define a hierarchy .. - right? It appears I can change the sequences at one level of the tree nodes - but how to insert a next level ("child" node) in the tree?
    So far I can build a flat tree (just one level of items).
    --
    How best change a private method to become public?
  • So, from what I remember, enyo.Node's defaultKind is enyo.Node, so you just node.createComponent() to add a new level to the "tree."

    I'm not sure we have an official process for going from "private" to "public" method. You might start a thread on the enyo-dev mailing list about it.

    I'm making my determination about it being private based on looking at the source code and seeing that it is listed after the last comment that says /* Private */
  • edited May 2013
    OK - thanks.
    Looks like I had trouble in referencing the created nodes.
    (Is there a better way than in my code below?)
    Now I got it working somewhat. (I can create hierarchy - but the addBefore: does not work as I expected)
     
    this.$.root.createComponent({content: "Europe", name: "europe", expandable:true, expanded: true});
    this.$.root.$.europe.createComponent({content: "Germany", name: "germany", expandable:true, expanded: true});
    this.$.root.$.europe.$.germany.createComponent({content: "Berlin", name: "berlin", expandable:true, expanded: true});
    this.$.root.$.europe.createComponent({addBefore: this.$.root.$.europe.$.germany , content: "Italy", name: "italy", expandable:true, expanded: true });
    
    Italy was inserted - but not before Germany.
  • edited May 2013
    never never NEVER use more than this.$ hash else you are breaking encapsulation. When you add a named component (like your first this.$.root.createComponent call there) THAT new named component will be owned by the component you created it in (this.$.root in your case), you need to set its owner property to _this_ so you can access it via this.$.europe.

    I have to say I've never tried to use addBefore, I just know it exists)
  • See this fiddle for a REALLY simple example: http://jsfiddle.net/sugardave/5vWVM/
  • @sugardave - thanks a lot for your help !
    Yes, the owner parameter did the trick. (First I assumed "this" is the default owner anyway.)
    Thanks for your jsfiddle. I see it working fine.
    So far I had used this.render() in my code and this somehow voids the addBefore.
    See you modified jsfiddle where I only added a this.render() below your italy.render(): http://jsfiddle.net/martinh_hp_open/5vWVM/4/
    Why does this.render() destroy the addBefore ?
  • Still wonder why does this.render() destroy the order that I introduce with the addBefore parameter ?
    Smells like a bug to me. Or what am I doing wrong here:
    http://jsfiddle.net/martinh_hp_open/5vWVM/4/
    ---
    I also managed to use a variable country instead of using the hardcoded string value ("italy" in our example) - but I don't like my code to check if the country already exists in the tree for which I use this code line:
    if (eval("this.$."+country)) return;
    See my working fiddle:
    http://jsfiddle.net/martinh_hp_open/p4SAg/
    Is there a better way to avoid using the eval() ?
    (Sorry, if this is a JavaScript beginners question)
  • Agree it's a bug. Looks like enyo.UiComponent isn't passing the addBefore parameter downstream when it has a controlParent. Here's the offending line. Comment indicates it was intentional but when i monkey patch the addBefore back in, your example works.

    ---
    Use if(this.$[country]) return; instead
  • I was also going to say this is a likely bug, but I couldn't post to the forums from the plane. I think Vanilla has problems with IPv6-only addresses :/
  • edited May 2013
    Thanks @theryanjduffy & @sugardave !
    OK - so I will consider submitting a bug report for the addBefore.
    At this time I do not really need the addBefore myself as I can sort my data first and then build the tree.
    ---
    Now I ["like"] these brackets very much more.
    And now the country names may include "." and " " (blanks) like in "Washington D.C." :)http://jsfiddle.net/martinh_hp_open/TkH8d/
  • > OK - so I will consider submitting a bug report for the addBefore.
    It appears that this is a known unresolved issue - reported for 2.0.1 already:
    https://enyojs.atlassian.net/browse/ENYO-1337 : Node do not support insertion of sub-nodes
    I added Ryans finding as a comment.
Sign In or Register to comment.