1

How to read XML and append in view with Backbone.

XML file has been read and successfully appended in view. But i don't know how to approach in Backbone structure (Using its Model).

XML file (read asseturl , width, height)

<library>
    <assets>
        <asset asseturl="img_1.png" width="100" height="150"></asset>
        <asset asseturl="img_2.png" width="200" height="250"></asset>
        <asset asseturl="img_3.png" width="300" height="350"></asset>
    </assets>
</library>

Backbone js code

var Book = Backbone.Model.extend();

var Books = Backbone.Collection.extend({
    model: Book,
    url: "file.xml",

    parse: function (data) 
    {
        var $xml = $(data);

        return $xml.find('assets').map(function() 
        {      
            var bookTitle = $(this).find('asset').each(function(){
            var this_url = $(this).attr('asseturl');
            var this_width = $(this).attr('width');
            var this_height = $(this).attr('height');

            $('.character-list').append('<li><span class="asset char">'+
            '<img width="'+this_width+'" height="'+this_height+'" src="'+this_url+'">'+
            '</span></li>');
        });
        return {title: bookTitle};
        }).get();
    },
    fetch: function (options) 
    {
        options = options || {};
        options.dataType = "xml";
        return Backbone.Collection.prototype.fetch.call(this, options);
    }
});

var bookListView = Backbone.View.extend({
    initialize: function () 
    {
        this.listenTo(this.collection, "sync", this.render);
    },
    render: function () 
    {
        console.log(this.collection.toJSON());
    }
});

var bks = new Books();
new bookListView({collection: bks});
bks.fetch();

HTML code to append

<ul class="character-list">
</ul>

Even-though the above append functionality works for me, it's not good practice to approach this in Backbone parse function.

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
ArunValaven
  • 1,753
  • 2
  • 25
  • 44
  • What you might want to do is create models for each of the assets in your parse function and add them to the assets collection. In your listView you may render them like you did in the parse function or a better way is to create a view for each model and let the view render itself. That will be a more backbone way of dealing with models & views. – Winter Soldier Nov 21 '16 at 16:22
  • Here are a few posts that can help you. [post1](http://stackoverflow.com/questions/6933524/a-backbone-js-collection-of-multiple-model-subclasses/6934682#6934682), [post2](http://stackoverflow.com/questions/40510330/add-new-collection-to-parent-view-from-child-view) – Winter Soldier Nov 21 '16 at 16:26

1 Answers1

1

Don't put the rendering logic into the collection's parse function.

The collection's role is to manage models and syncing with an API. It's the view's responsibility to render.

First, let's simplify the collection parsing. From the Backbone documentation, parse should do the following only:

The function is passed the raw response object, and should return the array of model attributes to be added to the collection.

parse: function(response) {
    var $xml = $(response);

    // this will return an array of objects
    return $xml.find('assets').children('asset').map(function() {
        var $asset = $(this);

        // returns raw "model" attributes
        return {
            asseturl: $asset.attr('asseturl'),
            width: $asset.attr('width'),
            height: $asset.attr('height')
        };

    }).get();
},

Then, make a simple view for each asset:

var BookView = Backbone.View.extend({
    tagName: 'li',
    template: _.template('<span class="asset char"><img width="<%= width %>" height="<%= height %>" src="<%= asseturl %>"></span>'),
    render: function() {
        this.$el.html(this.template(this.model.toJSON()));
        return this;
    }
});

And it's in the list view that the rendering of each assets is handled.

var BookListView = Backbone.View.extend({
    initialize: function() {
        this.childViews = [];
        this.listenTo(this.collection, "sync", this.render);
    },
    render: function() {
        this.$el.empty();
        this.collection.each(this.renderBook, this);
        return this;
    },
    renderBook: function(model) {
        var view = new BookView({ model: model });
        this.childViews.push(view);
        this.$el.append(view.render().el);
    },
});

To use it:

var bks = new Books(),
    view = new BookListView({ el: $('.character-list'), collection: bks });
view.render();
bks.fetch();
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
  • @ Emile Bergeron... Thanks for solving the issue.. Please reply for my future queries arise by me regarding the above given code.. – ArunValaven Nov 22 '16 at 14:05