1

I'm trying to pass a template to my view. I have several different templates I want to use and want to be able to switch them up in my router. I get no errors, but I get no results. It looks like the initialize method isn't being called in my second view. Here is my code:

   (function() {
        window.App = {
            Models: {},
            Collections: {},
            Views: {},
            Router: {}
        };

        window.template = function(id) {
            return _.template( $('#' + id).html() );
        };

        var vent = _.extend({}, Backbone.Events);

        _.templateSettings.interpolate = /\[\[(.+?)\]\]/g;

        App.Router = Backbone.Router.extend({
            routes: {
                '' : 'index',
                'send-message' : 'sendMessage',
                '*other' : 'other'
            },
            index: function() {
                t = new (App.Collections.Tables.extend({ url: 'main-contact'}))();
                tables = new (App.Views.Tables.extend({
     collection: t, template: template('mainContactTemplate')}))();
                $('#web-leads').html(tables.el);
            },
            sendMessage: function() {
                t = new (App.Collections.Tables.extend({ url: 'send-message'}))();
                tables = new App.Views.Tables.extend({
     collection: t, template: template('sendMessageTemplate')});
                $('#web-leads').html(tables.el);
            },
            other: function() {

            }
        });

        // Main Contact
        App.Models.Table = Backbone.Model.extend({});

        App.Collections.Tables = Backbone.Collection.extend({
            model: App.Models.Table,
            initialize: function(models, options) {
                this.fetch({
                    success: function(data) {
                        //console.log(data.models);
                    }
                });
                if (options) {
                    this.url = this.url || options.url;
                }
            }
        });

        App.Views.Tables = Backbone.View.extend({
            tagName: 'ul',
            initialize: function() {
                this.collection.on('reset', this.render, this);
            },
            render: function() {
                return this.collection.each(this.addOne, this);
            },
            addOne: function(model) {
                var t = new App.Views.Table({ model: model, template: template});
                this.$el.append(t.render().el);
                return this;
            }
        });

        App.Views.Table = Backbone.View.extend({
            tagName: 'li',
            template: this.template,
            initialize: function (attrs) {
                this.options = attrs;
                console.log(this.options);
            },
            render: function() {
                this.$el.html(this.template(this.model.toJSON()));
                return this;
            }
        });



        new App.Router();
        Backbone.history.start();
    })();

EDIT: I was missing some parenthesis. But now I get an error of an unrecognized expression. Initialize is now being called.

sehummel
  • 5,476
  • 24
  • 90
  • 137

1 Answers1

3

The way you are doing it in App.Views.Table is (as far as I can tell) the "standard" way of using templates with Backbone. There are of course several alternatives though, and none of them are "wrong" per say.

That being said, you do have a couple problems in your code. Let's start with:

template: this.template,

At the time that code runs you're not in an instance of App.Views.Tables, you're in the global space declaring a class that (later) will be used to make instances. At that moment though, this just refers to window. What you really want to do is set the template in your initialize, which leads me to:

initialize: function(options) {
     this.template = options.template;
},

But then there's one last problem:

var t = new App.Views.Table({ model: model, template: template});

there is no template variable in that function, so you're really doing template: undefined. That should use a real template.

All that being said, you might want to just consider putting the template on the view directly, the way you sort of tried to:

template: Handlebars.compile('<span>{{test}}</span>'),

After all, any given view should always use the same template, right? Also, you might want to consider moving the:

render: function() {
    this.$el.html(this.template(this.model.toJSON()));
    return this;
}

in to a parent class, so that you can share it between all of your templated views, instead of having to repeat it.

machineghost
  • 33,529
  • 30
  • 159
  • 234
  • Not all of my views are going to use the same template. I'm trying to dynamically switch templates. – sehummel Jan 08 '13 at 18:02
  • Also, it seems like you've removed my ability to dynamically switch the URL. I'm trying to write code that will let me switch the templates and the URLs in the router. I'm trying to avoid duplication of code. Those two things are the only differences in what I need to do multiple times based on each route. – sehummel Jan 08 '13 at 18:05
  • Right, but you can put a different template in each view. You can do: `var View1 = Backbone.View.extend({template: template1}); var View2 = Backbone.View.extend({template: template2});` – machineghost Jan 08 '13 at 18:05
  • I have no idea what you are talking about with "switching the URL"; the code I mentioned has nothing to do with the router. Perhaps you're confused about how views/routers/urls connect? – machineghost Jan 08 '13 at 18:06
  • In this line `t = new (App.Collections.Tables.extend({ url: 'send-message'}))();` I am passing in a URL that varies based on route. – sehummel Jan 08 '13 at 18:07
  • See how it is different in the two routes? – sehummel Jan 08 '13 at 18:09
  • My template is fairly complex. I don't want to put it inline in the view. – sehummel Jan 08 '13 at 18:11
  • Also, I'm not using Handlebars. – sehummel Jan 08 '13 at 18:12
  • Do you mean `t = new (App.Collections.Tables.extend({ url: 'send-message'}))();`? First of all, I said nothing about changing them in my answer, so I'm still confused. Second, that's unnecessary: what you're doing there is making a new view and then instantiating it, but you don't need a new view at all, you can just do: `t = new (App.Collections.Tables({ url: 'send-message'}));` – machineghost Jan 08 '13 at 18:13
  • Neither the inline part nor the Handlebars part are important; use whatever templating system you want and compile it wherever you want. The point is, you want to set it as the template property of the view class. I feel like maybe you're taking what I write too literally: I'm trying to help explain concepts here, not write your code word for word for you ;-) – machineghost Jan 08 '13 at 18:14
  • I'm confused about the two lines with `t` in them. That's where I think our communication broke down. Do you mind if we move to chat? – sehummel Jan 08 '13 at 18:15
  • OK, well thanks for your help. I'll try to take what you said a little less literally. – sehummel Jan 08 '13 at 18:21
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/22410/discussion-between-machineghost-and-sehummel) – machineghost Jan 08 '13 at 18:25