Backbone collections representing tree data

2019-03-14 13:40发布

问题:

I want to load json data in form of a tree into Backbone Collection. I can't do this. Can anyone explain what I'm doing wrong?

My very simple model:

CTreeDataItem = Backbone.Model.extend(
{
});
CTreeDataItems = Backbone.Collection.extend(
{
    model: CTreeDataItem
});

And my load attepmt:

    var treeJs =
        [
            { id: "tvRoot", title: 'Root', cssClass: 'root',
                items: [
                    { id: "ti1", title: 'Item1', cssClass: 'item',
                        items: [
                            { id: "ti11", title: 'SubItem11', cssClass: 'subitem'},
                            { id: "ti12", title: 'SubItem12', cssClass: 'subitem'}]},
                    { id: "ti2", title: 'Item2', cssClass: 'item',},
                    { id: "ti3", title: 'Item3', cssClass: 'item', 
                        items: [
                            { id: "ti31", title: 'SubItem31', cssClass: 'subitem'},
                            { id: "ti32", title: 'SubItem32', cssClass: 'subitem'},
                            { id: "ti33", title: 'SubItem33', cssClass: 'subitem'}]}]
        }];
    this.TreeData = new CTreeDataItems();
    this.TreeData.add(treeJs);

回答1:

Try representing the tree with Model as the node and each node containing a Collection of its child nodes:

var CTreeDataItem = Backbone.Model.extend({
    initialize: function() {
        if (Array.isArray(this.get('items'))) {
            this.set({items: new CTreeDataItemChildren(this.get('items'))});
        }
    }
});

// children collection
var CTreeDataItemChildren = Backbone.Collection.extend({
    model: CTreeDataItem
});

// create
var treeData = new CTreeDataItemChildren(treeJs);

// access
treeData.at(0).get('items').at(1).get('title')
// returns "Item2"

EDIT 2011-05-18: If you want to flatten the tree and maintain a reference to the parent that each node had in the tree:

// flatten the tree outside of Backbone. Alternatively,
// you could override the constructor of the CTree collection
// to provide encapsulation
function flatten(parentID, arr) {
    var out = [];
    for (var i = 0; i < arr.length; i++) {
        var node = arr[i];
        node.parentID = parentID;
        out.push(node);
        if (Array.isArray(node.items))
            Array.prototype.push.apply(out, flatten(node.id, node.items));
        delete node.items;
    }
    return out;
}

// remove above code that would have provided nesting
var CTreeDataItem = Backbone.Model.extend({});

// children collection, as before 
var CTreeDataItemCollection = Backbone.Collection.extend({
    model: CTreeDataItem
});

// create
var treeData = new CTreeDataItemChildren(flatten('', treeJs));

// as before, but now there's the 'parentID' FK
treeData.at(3).get('parentID')
// returns "ti1"

Hope that's what you're after.



回答2:

You need to use Backbone.Model parse method which is used to parse data before it gets passed to a model. You can use it to turn data on each level of your tree to Collections and Models representing items on these collections.

Then when saving you'd have to override the toJSON method on the Model to return the json representation of your data the same way you receive it. It is later on used by Backbone.sync to send the data back to the server. By default it returns only _.clone of your Model.attributes and you want all the Collections and CollectionModels in there as well.

All hail the backbone! :)