Skip to content Skip to sidebar Skip to footer

How Do I Pass A Received Array Into Underscore Template

I am getting a long array from PHP containing various data objects. [{'commid':'1','uid':'0','pid':'3','comment':'comm','parid':null,'date':'2016-10-27 15:03:10'}, {'commid':'2','u

Solution 1:

You should take advantage of Backbone's features. And to do that, you need to understand how to use a REST API with Backbone.

Backbone's Model is made to manage a single object and handle the communication with the API (GET, POST, PATCH, PUT requests).

Backbone's Collection role is to handle an array of model, it handles fetching it (GET request that should return a JSON array of objects) and it also parse each object into a Backbone Model by default.

Instead of hard-coding a jQuery ajax call, use a Backbone collection.

var WorkCollection = Backbone.Collection.extend({
    url: "includes/server_api.php/work",
});

Then, modularize your views. Make an item view for each object of the array you received.

var WorkItem = Backbone.View.extend({
    // only compile the template once
    template: _.template($('#content-box').html()),
    render: function() {

        // this is how you pass data to the template
        this.$el.html(this.template(this.model.toJSON()));

        return this; // always return this in the render function
    }
});

Then your list view looks like this:

var WorkPage = Backbone.View.extend({
    initialize: function(options) {
        this.itemViews = [];
        this.collection = new WorkCollection();

        this.listenTo(this.collection, 'reset', this.render);

        // this will make a GET request to
        // includes/server_api.php/work
        // expecting a JSON encoded array of objects
        this.collection.fetch({ reset: true });
    },
    render: function() {
        this.$el.empty();
        this.removeItems();
        this.collection.each(this.renderItem, this);
        return this;
    },

    renderItem: function(model) {
        var view = new WorkItem({
            model: model
        });
        this.itemViews.push(view);
        this.$el.append(view.render().el);
    },
    // cleanup to avoid memory leaks
    removeItems: function() {
        _.invoke(this.itemViews, 'remove');
        this.itemViews = [];
    }

});

It's unusual to set the url in the render function, you should keep the responsibilities scoped to the right place.

The router could be something like:

var Router = Backbone.Router.extend({
    routes: {
        'work': 'workPage'
    },

    workPage: function() {
        var page = new WorkPage({
            el: $('#indexcontent'),
        });
    }
});

Then, if you want to see the work page:

var myRouter = new Router();

Backbone.history.start();

myRouter.navigate('#work', { trigger: true });

Templates and RequireJS

My index.html page contains this indexcontent div but the content-box which contains the template format which we are compiling is stored in different work.html. So, if i dont load this work.html in my main index.html i am unable to access content-box.

I would recommend to use the text require.js plugin and load each template for the view like this:

The work-item.js file:

define([
    'underscore', 'backbone',
    'text!templates/work-item.html',
], function(_, Backbone, WorkItemTemplate) {
    var WorkItem = Backbone.View.extend({
        template: _.template(WorkItemTemplate),
        /* ...snip... */
    });
    return WorkItem;
});

The work-page.js file:

define([
    'underscore', 'backbone',
    'text!templates/work-page.html',
], function(_, Backbone, WorkPageTemplate) {
    var WorkPage = Backbone.View.extend({
        template: _.template(WorkPageTemplate),
    });
    return WorkPage;
});

Solution 2:

In your index.html file you need to have _.each() method to iterate throught each element

<% _.each(obj, function(elem){ %>
<div class="workhead">
    <h3 class="msg comment"><%= elem.comment %></h3>
    <p class="date"><%= elem.date%></p>
</div>
<% }) %>

I make variable of your response just to have data to work with. In your View you need to set point on template template: _.template($("#content-box").html()), and in render method just send data as object.

Here is working code : jsFiddle


Solution 3:

Here is one way to load the template for each value in the data array.

var WorkPage = Backbone.View.extend({
    el: $('#indexcontent'),
    render: function() {
        Backbone.history.navigate('work');
        var _this = this;

        this.$el.html(workHTML);
        $.ajax({
            type: "GET",
            url: "includes/server_api.php/work",
            data: '',
            cache: false,
            success: function(data) {
                console.log(data);
                var $div = $('<div></div>');
                _.each(data, function(val) {
                    $div.append(_.template($('#content-box').html(), val));
                });
                _this.$el.html($div.html());
            },
            error: function(e) {
                console.log(e);
            }
        });
        return false;
    }
});

Post a Comment for "How Do I Pass A Received Array Into Underscore Template"