Encontre abaixo a reprodução mais concisa que consegui imaginar de uma sequência de etapas em um aplicativo de Backbone que leva Collection
a um estado de confusão interna.
Uma cópia de trabalho pode ser encontrada neste JSFiddle .
O que ele demonstra é um collection
mantendo uma referência interna ( _byId
) para um remove()
-ed Model
. Esse Model
não faz mais parte de collection.models
, no entanto, ele ainda pode ser recuperado por meio de seu (antigo) id
.
var
MyView = Backbone.View.extend( {
initialize: function () {
this.model = new Backbone.Model( {
id: 'foo'
, foo: 'bar'
} );
this.collection = new Backbone.Collection( this.model );
this.listenTo( this.model, 'change:id', function ( model, id ) {
if ( id == null ) {
this.collection.remove( model );
}
} );
this.model.unset( 'id' );
$('#models' ).val( JSON.stringify( this.collection.models ));
$('#_byId' ).val( JSON.stringify( this.collection._byId ));
$('#get-foo').val( JSON.stringify( this.collection.get( 'foo' )));
}
})
, foo = new MyView()
;
Hmm interessante. Quando adicionamos o modelo à coleção, __byId_ adiciona duas propriedades: model.id e model.cid, sua referência ao modelo. Problema na linha 1134, id === indefinido , mas __byId_ contém model.id - _'foo'_.
A coleção não tem uma lógica especial ao alterar model.id para value == null , verifique a linha 1183.
Além disso, você pode alterar não definido para this.model.set ('id', nulo);
PS: Eu acho que você nunca precisa definir o id do modelo como nulo ou indefinido, é anti-padrão.
Sim - você nunca deve fazer isso, mas ainda é um bug.
Devemos corrigir isso nos certificando de que se um id
está mudando de um valor para null
, nós delete this._byId[id]
primeiro.
Se você remover um modelo de uma coleção sem o uso de um evento, ele funcionará conforme o esperado. O problema está em _onModelEvent
que verifica se o nome do evento é change
, quando o nome do evento real sendo enviado neste caso é change:id
.
Comentários muito úteis
Sim - você nunca deve fazer isso, mas ainda é um bug.
Devemos corrigir isso nos certificando de que se um
id
está mudando de um valor paranull
, nósdelete this._byId[id]
primeiro.