javascript - Backbone : Re-render existing model in new DOM element

标签 javascript backbone.js underscore.js

我正在使用 Collection View 来渲染模型 View 数组。我添加了一个方法,该方法从现有 Collection View 中删除单个模型 View ,并尝试在新的 el: 元素中重新渲染它。

我使用collection.get(this.model)将模型保存到一个变量中,我将该变量添加到我的新集合中,该集合是与新DOM关联的新 Collection View 的模型元素,并且我重新使用相同的 Collection View 渲染方法。当我 console.log() 新集合时,我看到了从旧集合中选取的模型,但它没有在页面上呈现。

<script>

    (function($){

    //---------SINGLE ENTRY MODEL----------
            var Entry = Backbone.Model.extend({
                defaults: function(){
                    return{
                        word: '',
                        definition: ''
                    }
                }
            });

        //------------ENTRY MODEL COLLECTION------------
            var EntryList = Backbone.Collection.extend({
                model: Entry
            });

        //-----INSTANCIATE COLLECTION----
        var dictionary = new EntryList();
        var saved = new EntryList();

        //-----SINGLE ENTRY VIEW------
        var EntryView = Backbone.View.extend({
            model: new Entry(),
            tagName:'div',

            events:{
                'click .edit': 'edit',
                'click .delete': 'delete',
                'keypress .definition': 'updateOnEnter',
                'click .save': 'save'
            },

            delete: function(ev){
                ev.preventDefault;
                dictionary.remove(this.model);

            },

            edit: function(ev){
                ev.preventDefault;
                this.$('.definition').attr('contenteditable', true).focus();

            },
            //method that adds existing model to new collection
            save: function(ev){
                ev.preventDefault;
                var savedEntry = dictionary.get(this.model);
                dictionary.remove(this.model);
                saved.add(savedEntry);
                console.log(savedEntry.toJSON());

            },
            close: function(){
                var definition = this.$('.definition').text();
                this.model.set('definition', definition);
                this.$('.definition').attr('contenteditable', false).blur();

            },

            updateOnEnter: function(ev){
                if(ev.which == 13){
                    this.close();
                }
            },

            initialize: function(){
                this.template = _.template($("#dictionary_template").html());

            },

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

        //--------------DICTIONARY VIEW------------
        var DictionaryView = Backbone.View.extend({
            model: dictionary,
            el: $('#entries'),

            initialize: function(){
                this.model.on('add', this.render, this);
                this.model.on('remove', this.render, this);

            },

            render: function(){
                var self = this;
                self.$el.html('');
                _.each(this.model.toArray(), function(entry, i){
                    self.$el.append((new EntryView({model: entry})).render().$el);
                });

                return this;
            }
        });

        //---------SAVED ENTRY VIEW-----------
        var SavedView = Backbone.View.extend({
            model: saved,
            el: $('#saved'),

            initialize: function(){
                this.model.on('save', this.savedRender, this);
            },
            //method that renders new collection view with different el: 
            savedRender: function(){
                var self = this;
                self.$el.html('');
                _.each(this.model.toArray(), function(saved, i){
                    self.$el.append((new EntryView({model: savedEntry})).render().$el);
                });

                return this;
            }
        });


        //-------BINDING DATA ENTRY TO NEW MODEL VIEW-------
        $(document).ready(function(){
            $('#new-entry').submit(function(ev){
                var entry = new Entry({word: $('#word').val(), definition: $('#definition').val()       });

                dictionary.add(entry);
                dictionary.comparator = 'word';

                console.log(dictionary.toJSON());

                $('.form-group').children('input').val('');

                return false;
            });
            var appView = new DictionaryView();
        });


        //--------------ROUTER----------------
        var Router =  Backbone.Router.extend({
            routes:{
                '':'home' 
            }
        });
        var router = new Router();
        router.on('route:home', function(){
            console.log('router home');
        });
        Backbone.history.start();
    })(jQuery); 

    </script>

最佳答案

这里存在很多问题。

首先,您没有 SavedView 的实例。 var SavedView = Backbone.View.extend(...); 语句只是定义 SavedView 。为了拥有此类的事件实例,您必须使用 new 运算符初始化一个实例。您将需要在代码中的某个位置添加如下行(一个好的位置是 jQuery 就绪处理程序的末尾):

var saved_view = new SavedView();

接下来,我们将研究EntryView类的save方法。 var savingEntry =dictionary.get(this.model); 语句完全没有必要,因为我们知道 dictionary.get(this.model) 将返回 this.model - 其中我们显然已经有一个实例了。因此,我们可以消除此方法中的困惑,并留下以下内容:

ev.preventDefault;
saved.add(this.model);
dictionary.remove(this.model); 

但是,我们还没有到达目的地。如果我们将注意力转向 SavedView 类定义,我们会看到它将其 render 方法绑定(bind)到其集合(即 saved 对象)上的“save”事件。它不是我们应该绑定(bind)的“保存”事件,而是“添加”事件 - 因为这是当我们将模型添加到已保存时将触发的事件:

this.model.on('add', this.savedRender, this);

如果我们现在测试我们的代码,我们应该会因 SavedView.savedRender 内的 savedEntry 上的引用错误而受到责骂。看起来这是一个错字,本来的意思是“已保存”。 (您会在下面注意到,除了纠正拼写错误之外,我还从此表达式中删除了一组括号,这些括号除了降低代码的可读性之外没有任何作用):

self.$el.append(new EntryView({ model: saved }).render().$el);

编辑:

回答您关于 SavedView.savedRender 方法中的 saved 变量的后续问题:

本例中保存的对象单个Entry模型。您感到困惑的原因是我们重复使用变量名称“saved”。在 _.each 回调中,我们定义了第一个参数“saved”;此“已保存”是回调的本地内容,与之前定义的 EntryList 集合无关。在我们的回调中,savedsaved 集合的一个元素(哎呀!)——这就是为什么变量命名很重要的一个教训。

当我继续更改 savedRender 方法中“saved”的名称时,我注意到还有一些其他重构需要进行。我在下面列出了我的重构:

  1. 使用 Backbone ( http://backbonejs.org/ ) 的目的是让我们能够访问对象(模型)和数组(集合)的方便助手。 Backbone 集合有一个 each 方法,我们可以使用它来代替将我们的集合传递给 Underscore 的 ( http://underscorejs.org/ ) each

  2. 如上所述,saved 对于我们的 each 回调参数来说是一个糟糕的名称,因为它在概念上与集合的名称冲突。由于 saved 是 Entry 模型的集合,因此“entry”是一个更合适的名称。

  3. Backbone 允许我们将上下文传递给每个回调,该回调将成为该回调中的 this。这允许我们跳过在 self 变量中缓存 this 的步骤。

我重构后的 savedRender 变为:

savedRender: function () {    
    this.$el.empty();
    this.model.each(function (entry) {
        this.$el.append(new EntryView({ model: entry }).render().$el);
    }, this);    

    return this;
}

关于javascript - Backbone : Re-render existing model in new DOM element,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27576322/

相关文章:

javascript - 如何避免在 Backbone 中使用空 div 进行模板包装?

javascript - 下划线 _.clone() 不适用于 Parse JS SDK 复合查询

javascript - underscorejs 将带冒号的字符串传递给它时,会根据环境呈现不同的结果

javascript - 右键单击时出现两次警报

javascript - MySQL 数据库中上传文件夹的 Multer 文件地址格式不正确

javascript - Angular BehaviourSubject 仅在组件加载时触发订阅一次

javascript - 带有谷歌地图的 Backbone.js - 这个问题和听众

javascript - 如何用jquery限制多个元素的字符串长度?

javascript - Backbone UI 模型与 Handlebars 绑定(bind)

javascript - 通过它的 id 从数组中删除一个对象( Angular )