0

Backbonejs を使用して ul に li を追加および削除するための小さなアプリを作成していました。SO メンバーの cymen の 1 人がコーディングを手伝ってくれました。 2回目に要素を(ulに)追加して削除すると、取得します

Uncaught TypeError: undefined のメソッド 'remove' を呼び出せません

ここに私のコードを貼り付けて、

HTML :

<input type="text" id="name">
<button id="add">Add</button>
<ul id="mylist"></ul>

JS:

$(function(){

        var myCollection = Backbone.Collection.extend();

        var myView = Backbone.View.extend({

            el:$('body'),

            tagName:'li',

            initialize : function(e){
                this.collection.bind("add",this.render,this);
                this.collection.bind("remove",this.render,this);
            },

            events:{
                'click #add' : 'addfoo'                
            },

            addfoo : function(){
               var myname= $('#name').val();
               $('#name').val('');               
               this.collection.add({name:myname});
            },

            render : function(){

                $('#mylist').empty();
                this.collection.each(function(model){
                    console.log("myView");
                    var remove = new myRemoveView({model:model});
                    remove.render();
                });
            }
        });

        var myRemoveView = Backbone.View.extend({

        el:$('body'),

        events:{
            'click .button':'removeFoo'
        },

        removeFoo : function(){
            console.log("here");

            this.model.collection.remove(this.model);
        },

        render : function(){
            console.log("second view");
            $('#mylist').append('<li>'+this.model.get('name') + "<button class='button'>"+"delete"+"</button></li>");
            return;
        }


        });
        var view = new myView({collection: new myCollection()});
            });

私が理解していなかった2つのこと:

i) removeFoo 関数で、次のように記述します。

this.model.collection.remove(this.model)

これは this.collection.model.remove 、そのようなものであるべきではありませんか?

ii) ul に li を追加し、それを削除します。別の li を追加すると (ul への追加は完璧に機能します)、今回は削除しようとすると上記のエラーがスローされます: Uncaught TypeError : cannot call method 'remove'未定義の

私のコードでこれらの2つの疑問を理解するのを手伝ってもらえますか.ところで、SOメンバーのcymenのコードは、私の調整されたコード(上記)だけが私にエラーを与えているだけです.

SO メンバー cymen のコード :彼のコードの JS Fiddle

ありがとうございました

4

1 に答える 1

2

まず第一に、あなたmyRemoveViewは次のように使用<body>していますel:

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

つまり、削除ボタンを押すたびに、作成removeViewしたすべてのシングルでトリガーされmyRemoveViewます。それは確かにあなたが望んでいることではなく、cymen が使用している理由の一部ですtagName: 'li'。ビューとそのビューには、次の 2 つの一般的なルールがありますel

  1. ビューごとelに 1 つ、ビューごとに 1 つelelイベント処理の問題のため、同じビューを共有したくありません。二重に、同じビューの複数のインスタンスがel.
  2. ビューelは、ビューが気にする DOM の一部である必要があります。それ以上でもそれ以下でもありません。これにより、クリーンアップが非常に簡単になります。ビューに関連付けられた DOM 要素を削除するだけで、ほとんどのもの (特に DOM イベント) がなくなります。非 DOM イベントの場合、removeビューに対するメソッドがあります。

もう1つのことは、ビューが(一般に)それ自身の外側のDOMをいじってはならないということelです。これは非常に奇妙に見えます:

render : function(){
    $('#mylist').append(...);
    return;
}

呼び出し元はel、あなたがどこに行くのかを理解する責任があるべきです#mylist. また、renderメソッドは慣習的に戻りthis、これを行うことができます:

$(x).append(some_view.render().el);

それらをDOMに入れます。

tagNameビューでとの両方を指定elする:

var myView = Backbone.View.extend({
    el: $('body'),
    tagName: 'li',

は無意味であり、tagName無視されてel使用されます。

また、フィドルで Backbone 0.5.3 を使用しています。可能な限り最新バージョンを使用する必要があります。

上記を修正すると、すべてが機能し始めます(再び):

var myView = Backbone.View.extend({
    //...
    render: function() {
        $('#mylist').empty();
        this.collection.each(function(model) {
            var remove = new myRemoveView({
                model: model
            });
            $('#mylist').append(remove.render().el);
        });
    }
    //...
});

と:

var myRemoveView = Backbone.View.extend({
    tagName: 'li',
    //...
    render: function() {
        this.$el.text(this.model.get('name'));
        this.$el.append("<button class='button'>delete</button>");
        return this;
    }
});

デモ: http://jsfiddle.net/ambiguous/2z4SA/1/


では、元のバージョンではどのようなクレイジーが起こっていたのですか? 鍵はel: $('body')あなたの中にありますmyRemoveViewmyRemoveView最初に、何が起こっているかを簡単に監視できるように、小さなロギング メソッドを追加します。

_log: function(method) {
    console.log(
        method,
        ': model =', this.model.cid,
        ' got-collection =', this.model.collection ? 'yes' : 'no',
        ' view =', this.cid
    );
}

cidは Backbone が作成する内部固有の ID であり、物事を追跡するための便利な方法であることに注意してください。次にthis._logremoveFooandを呼び出しrenderます。

removeFoo: function() {
    this._log('removeFoo');
    if(this.model.collection)
        this.model.collection.remove(this.model);
},
render: function() {
    this._log('render');
    $('#mylist').append('<li>' + this.model.get('name') + "<button class='button'>" + "delete" + "</button></li>");
    return;
}

これは、すべてがうまくいかなかったことを示す簡単なプロセスです。

  1. aを下のリストに加える。
  2. bを下のリストに加える。
  3. 削除ボタンを押します。

ここに従うことができます:http://jsfiddle.net/ambiguous/yLYNL/

最初に a を追加すると、コンソールに次のポップアップが表示されます。

render : model = c1  got-collection = yes  view = view2

次にbを追加すると、次のようになります。

render : model = c1  got-collection = yes  view = view4
render : model = c3  got-collection = yes  view = view5

rendermyViewはコレクション全体を再描画するc1ため、 ac3新しいbが表示されます。これまでのところ、すべてが理にかなっています。

では、 ;を削除しようとします。removeFoo最初に次のことがわかります。

removeFoo : model = c1  got-collection = yes  view = view2

これmyView#renderにより、コレクション全体が再描画されます。コレクション全体はこの時点でただのbであるため、再びレンダリングされたことがわかりc3、すべてが意味をなします:

render : model = c3  got-collection = yes  view = view6

しかし今、すべてが横向きになっていることがわかります。

removeFoo : model = c1  got-collection = no   view = view4
removeFoo : model = c3  got-collection = yes  view = view5 

c32 つのmyRemoveViewインスタンス ( a用とb用) が同じものにバインドされているため、表示されることがわかります。elそのため、両方がclick .deleteイベントを表示しc1ます。最初に表示されるのはたまたまです。

しかし、それはそこで何をしているのc1ですか?それはコレクションを持たないものであり、元のエラーを引き起こしているものです。myRemoveViewをイベントから切り離さないため<body>、ゾンビが発生します。<li>がなくなっても、ビューは<body>ビューのdelegate呼び出しによってバインドされたままです。ゾンビ モデルを参照するゾンビ ビューがあり、どこにでもゾンビ ゾンビがいて、車内にゾンビ ファイティング キットを置き忘れました。しかし、なぜc1コレクションを持っていないのですか?さて、あなたはしました:

this.model.collection.remove(this.model)

onc1でコレクションから削除します。コレクションからモデルを削除すると、モデルのモデルが削除collectionされます。これは、モデルがコレクションに含まれていないためです。

于 2012-11-25T05:03:12.607 に答える