The Sheek Geek
The Sheek Geek

Reputation: 4216

Creating backbone views with models from other views

Background:

I am making changes to an application that uses backbone.js with Handlebars as the templating engine. After a change event fires I need to create html that is appended to the current DOM structure which is basically just a spit-out of information that is contained in the model. This change needed to fit in the already established application structure.

Issue:

I have created a new view that uses a Handlebars template and the model to create the html. I then instantiate that view and call the render function and append the output using JQuery. What I am noticing is that when the html is rendered the model that is passed in because attributes on the $el instead of filling in the template (like I think it should).

View I'm altering:

$.hart.TestView = Backbone.View.extend({
    tagName: "li",
    template: Handlebars.compile($('#templateOne').html()),
    initialize: function () {
        this.model.on('change', function () {
            this.createMoreInfoHtml();
        }, this);
    },
    selectSomething: function () {
        this.$el.removeClass('policies');

        this.createMoreInfoHtml(); //function created for new view stuff
    },
    createMoreInfoHtml: function () {
        var id = this.$el.attr('data-id', this.model.get("ID"));
        $('.info').each(function () {
            if ($(this).parent().attr('data-id') == id 
                $(this).remove();
        });

        var view = new $.hart.NewView(this.model, Handlebars.compile($("#NewTemplate").html()));
        $('h1', this.$el).after(view.render().el);
    },
    render: function () {
        ... //render logic
    }
});

View I Created:

$.hart.NewView = Backbone.View.extend({
        initialize: function (model, template) {
            this.model = model;
            this.template = template;
        },
        render: function () {
            this.$el.html(this.template({ info: this.model }));
            this.$el.addClass('.info');
            return this;
        }
    });

Json the is the model:

{
        "PetName":"Asdfasdf", 
        "DateOfBirth":"3/11/2011 12:00:00 AM",      
        "IsSpayNeutered":false, 
        "Sex":"F", 
        "SpeciesID":2, 
        "ID":"ac8a42d2-7fa7-e211-8ef8-000c2964b571"
    }

The template

<script id="NewTemplate" type="text/html">
        <span>Pet Name: </span>
        <span>{{this.PetName}}</span>
    </script>

So now to the question: What am I doing wrong? Why are the properties of the model being created as attributes on the $el instead of filling in the template? Can someone please direct me as to how to get the results I am looking for?

Upvotes: 0

Views: 106

Answers (1)

Loamhoof
Loamhoof

Reputation: 8293

Let's skip the problem Jack noticed.
The way you're creating your view is just wrong. It may work as you get the expected arguments in the initialize function, but it has unexpected behaviors you don't see. See the View's constructor:

var View = Backbone.View = function(options) {
  this.cid = _.uniqueId('view');
  this._configure(options || {});

Now let's have a look at this _configure method:

_configure: function(options) {
  if (this.options) options = _.extend({}, _.result(this, 'options'), options);
  _.extend(this, _.pick(options, viewOptions));

And of course...

var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];

Ok here we are... Basically when passing the model as the options argument, you're passing an object with an attributes key (the attributes of your model). But this attributes key is also used in the View to bind attributes to its element! Therefore the behavior your noticed.

Now, other wrong thing. You're compiling your template each time you create a new function, but not using it as a singleton either. Put your template in the view:

$.hart.NewView = Backbone.View.extend({
  template: Handlebars.compile($("#NewTemplate").html(),

And change your view's creation to make the whole thing work:

new $.hart.NewView({model: this.model});

Oh, and get rid of this useless initialize method. You're just doing things Backbone already does.

Upvotes: 1

Related Questions