user3821383
user3821383

Reputation: 31

flat list from nested elements in marionette

Is it possible in Marionette to generate a flat list out of a nested list of models and collections?

For instance i would like to generate a select element with each node as an option (child options should be indented):

[
  {
    nodeName: "top level 1",
    nodes: [
      {
        nodeName: "2nd level, item 1",
        nodes: [
          { nodeName: "3rd level, item 1" },
          { nodeName: "3rd level, item 2" },
          { nodeName: "3rd level, item 3" }
        ]
      },
      {
        nodeName: "2nd level, item 2",
        nodes: [
          { nodeName: "3rd level, item 4" },
          { nodeName: "3rd level, item 5"},
          { nodeName: "3rd level, item 6" }
        ]
      }
    ]
  }
]

This should become something like:

<select>
    <option>top level 1</option>
    <option>   2nd level, item 1</option>
    <option>      3nd level, item 1</option>
    <option>      3nd level, item 2</option>
    <option>      3nd level, item 3</option>
    <option>   2nd level, item 2</option>
    ...
</select>

So far I have been trying with nested composite views (as in this fiddle http://jsfiddle.net/hoffmanc/NH9J6/), but I haven't been able to make it work properly.

Regards

Upvotes: 0

Views: 135

Answers (2)

booleanhunter
booleanhunter

Reputation: 5880

Have you considered using underscore.js's _.flatten() method? It could be much simpler. flattening nested arrays/objects in underscore.js

Upvotes: 0

Evgeniy
Evgeniy

Reputation: 2921

Sure, first recursively iterate over nested and create plain JSON with node text and nest level it has for padding:

var flat = [];

function parseJson(nodes){
    parseJson.level = parseJson.level || 0;        

    nodes.forEach(function(node, i){
        flat.push({ text:node.name, level: parseJson.level});
        if(node.nodes){
            parseJson.level++;
            parseJson(node.nodes);
        } 
        (i == nodes.length -1) && parseJson.level--;
    })
}

/* or you can get flat array with reduce */

var rawJson = [/* Your json here */], 
    flat = rawJson.reduce(function rec(memo, item, i, array){
        rec.level = rec.level || 0;
        memo.push({ text: item.n, level: rec.level });
        if(item.nodes){
            rec.level++;  
            item.nodes.reduce(rec, memo);
        }

        (i == array.length -1) && rec.level--;

        return memo;
}, []);

nodes is your raw json. In flat you will have elements like this:

{
    text: 'node text',
    level: 2
}

Next, create Model and Collection for view rendering:

var NodeModel = Backbone.Model.extend({
        defaults: {
            name: 'unnamed',
            level: 0
        }
    }),
    NodeCollection = Backbone.Collection.extend({
        model: NodeModel 
    });

Then Views:

var NodeView = Marionette.ItemView.extend({
        tagName: 'option',
        template: '#node-template'
    }),
    NodeCollectionView =  Marionette.CollectionView.extend({
        itemView: NodeView /* or childView if Marionette v 2.0.*/
    });

Then template:

<% _.times(level, function(){ %> &nbsp; <% }); %> <%= text %>

And finally:

(new NodeCollectionView({
  collection: new NodeCollection(flat),
  el: 'body'
})).render();

thats all) Hope this help;

Upvotes: 1

Related Questions