Underscore.js Template Issue - Невозможно вызвать метод replace вместо null

Я искал и нашел много ответов, но ни один, кажется, не работает.

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>
           Shopping Cart
        </title>
        <link rel="stylesheet" href="lib/style.css" type="text/css">
    </head>
    <body>
<script id="rtemp" type="text/x-underscore-template"">
            <span><%= title %></span>
    </script>
        <script src="lib/jquery.js" type="text/javascript"></script>
        <script src="lib/underscore.js" type="text/javascript"></script>
        <script src="lib/backbone.js" type="text/javascript"></script>
        <script src="lib/script.js" type="text/javascript"></script>
    </body>
    <script>
var Photo = Backbone.Model.extend({


    initialize: function(){
        console.log('this model has been initialized');

        this.bind("change:title", function(){
            var title = this.get("title");
            console.log("My title has been changed to.. " + title);
            var pv = new PhotoView();
            pv.render();
        });

    },

    setTitle: function(newTitle){
        this.set({ title: newTitle });
    },

    setLocation: function(newLoc)
    {
        this.set({location:newLoc});
    }
});

var PhotoView = Backbone.View.extend
({
    el: $('body'),

    render: function(event)
    {
        var name = myPhoto.get('title');
        console.info(name);
        var template = _.template($('#rtemp').html(), {title:name});
        console.info(this.model);
        $(this.el).html(template);
        return this;
    }

});



    </script>
</html>

Первый;

Создать новый экземпляр метода

 var newPhoto = new Photo();
 newPhoto.setTitle('Fishing');

Это отлично работает, он будет загружаться в тело через шаблон. Однако если я сделаю это снова,

newPhoto.setTitle('Sailing');

Я получаю сообщение об ошибке - "Невозможно вызвать метод" заменить " из нуля & quot;

Нет ошибки в строке, но я считаю, что это в

var template = _.template($('#rtemp').html(), {title:name});

Ответы на вопрос(1)

Решение Вопроса

Your template has a double " in the type attribute, it should be:

<script id="rtemp" type="text/x-underscore-template">

Your view's render is referencing myPhoto when it should be this.model:

var name = this.model.get('title');

And your main problem is that your view uses <body> as its this.el and your template is inside <body>.

Вы полностью заменяете содержание<body> когда вы предоставляете свой вид:

$(this.el).html(template);

так после первогоrender звони, больше нет#rtemp, Затем на следующемrender позвоните, попробуйте это:

var template = _.template($('#rtemp').html(), ...);

но с тех пор#rtemp больше нет в DOM, все разваливается.

Если вы сразу же взяли шаблон:

var PhotoView = Backbone.View.extend({
    el: $('body'),
    template: _.template($('#rtemp').html()),
    //...
});

а затем использоватьthis.template() вrender:

render: function(event) {
    //...
    var template = this.template({
        title: name
    });
    //...
}

тебе повезет больше. Разумеется, вам необходимо убедиться, что вы определяете свое представление в обработчике, готовом к документу, с помощью этого подхода или#rtemp может быть недоступно при определении вашего представления.

Демо-версия:http://jsfiddle.net/ambiguous/dwGsM/

Тем не менее, структура вашего приложения довольно странная. У вас есть модель, которая слушает себя, а затем модель создает и отображает представление, когда что-то меняется. Модель, слушающая себя, сама по себе хороша, но обычно у вас есть представления, слушающие модели, и представление будет повторно отображать себя (или только части себя) при изменении модели.

Ваша модель должна выглядеть примерно так:

var Photo = Backbone.Model.extend({
    setTitle: function(newTitle) {
        this.set({ title: newTitle });
    },
    setLocation: function(newLoc) {
        this.set({ location: newLoc });
    }
});

И тогда твоя точка зрения такая:

var PhotoView = Backbone.View.extend({
    el: $('body'),
    template: _.template($('#rtemp').html()),
    initialize: function() {
        _.bindAll(this, 'render');
        this.model.on('change:title', this.render);
    },
    render: function(event) {
        this.$el.html(
            this.template(this.model.toJSON())
        );
        return this;
    }
});

_.bindAll вinitialize гарантирует, чтоthis.render будет называться с правомthis; затемinitialize привязывается к событию, чтобы оно могло реагировать на изменения в модели. Представление знает, о чем заботится, поэтому оно отвечает за изменения в модели. И вrenderВы обычно просто звонитеtoJSON чтобы получить данные для шаблона. Кроме того, более новые версии Backbone включают в себя кэшированную версию$(this.el) по мнению какthis.$el так что вам не нужно$(this.el) себя больше.

Затем вы начинаете все так:

var newPhoto = new Photo();
var viewPhoto = new PhotoView({ model: newPhoto });
newPhoto.setTitle('Fishing');
newPhoto.setTitle('Sailing');

Вы сообщаете представлению, какую модель использовать, указавmodel опция при создании вида.

Вы также можете переместить шаблон<script> снаружи<body>.

Новая и улучшенная демоверсия:http://jsfiddle.net/ambiguous/Kytw7/

 18 янв. 2014 г., 14:17
& quot; Вы полностью заменяете содержание & lt; body & gt; когда вы отображаете вид. & quot; Благодарю вас!
 29 янв. 2013 г., 13:00
Отличные объяснения! 1. Мне было интересно, куда вы звонитеrender() если послеvar viewPhoto = new PhotoView({ model: newPhoto }); у вас нет каких-либо изменений в модели. 2. Как вы уменьшаете количество «рендеринга»? раз?
 mcclennon1913 июн. 2012 г., 14:26
Спасибо тебе, коротко, это очень помогло. Я бьюсь головой об этом, но ваше объяснение прояснило многие проблемы: D
 29 янв. 2013 г., 19:13
@serbanghita: Трудно сказать, без каких-либо подробностей, но вы, вероятно, просто позвоните ему вручную.

Ваш ответ на вопрос