2011-07-28 24 views
17

Tengo una vista de correo electrónico en mi aplicación Backbone. Actualmente está instanciado en la acción view de mi controlador. Se va un poco así:Al cambiar el modelo para una vista, ¿es mejor reemplazar el modelo o crear una vista nueva?

routes: { 
    'email/:id': email 
}, 

//... 

email: function (id) { 
    var email = new Email({ 
    id: id 
    }); 
    this.emailView = new EmailView({ 
    model: email 
    }); 
    email.fetch(); 
} 

Ahora, el problema es, si volviese a un correo electrónico, y luego otro, que terminan creando dos separados EmailView s. Esto significa que, por ejemplo, el enlace de eliminación en el EmailView está vinculado a dos modelos de Email por separado, por lo que al hacer clic en eliminar se eliminarán ambos (algo que no es bueno).

Estoy buscando dos soluciones. En uno, guardaría en caché el EmailView y actualizaría su modelo. El problema entonces es que tendría que volver a enlazar el events en EmailView.

La otra solución sería crear un nuevo EmailView como lo estoy actualmente, pero desvincular los eventos del viejo EmailView.el antes de reemplazarlo.

¿Voy por esto de la manera correcta? ¿Hay una mejor manera de manejar esta situación? Saludos de antemano.

Respuesta

3

Crea una instancia de vista separada para cada instancia de modelo. Cada vez que visita un nuevo correo electrónico, deseche la vista anterior y cree una vista nueva con la nueva instancia de correo electrónico.

Probablemente lo que tiene si lo estoy adivinando es una vista de lista en el lado izquierdo y un editor a la derecha. Seleccione el correo electrónico de la lista a la izquierda y desea que el cuerpo del correo electrónico aparezca a la derecha.

Usted realmente quiere aproximadamente 5 clases de vista.

PageView 
    has_one EmailCollectionView on left 
    has_one EmailEditorView on right 

EmailCollectionView 
    has_many EmailSummaryViews as vertical list 

EmailEditorView 
    has_one EmailView centered 

Al hacer clic en el EmailCollectionView activar un evento el cual es recogidos por EmailEditorView la que tira a la basura es viejo instancia de emailview y hace una nueva versión de emailview

Algo como eso de todos modos

+0

El único problema es que no se trata simplemente de tirar el viejo EmailView. Los detectores de DOM no están sueltos, por lo que impiden que la vista anterior sea recogida como basura. Luego, cuando alguien hace clic en 'eliminar', todos los viejos EmailViews los recogen. Creo que la respuesta es desvincular manualmente a esos oyentes antes de reemplazar la vista de correo electrónico. – Skilldrick

+0

Ahora me tiene preocupado por mi propio código;) – bradgonesurfing

+1

Mire el documento para jquery :: remove. http://api.jquery.com/remove/ a lo que Backbone.js llama. Los controladores de eventos se recogen automáticamente como basura para todos los elementos secundarios de la vista. Aún necesitaría desconectarse del encuadernado del modelo y los enlaces a otras vistas. Sin embargo, vincular a otras vistas es malo. Los eventos de Vista a Ver deben activarse a través de modelos. – bradgonesurfing

2

Originalmente creábamos nuevos objetos de vista cada vez que alguien navegaba, por ejemplo "candidates/show", al igual que el ejemplo del correo electrónico. Esa vista vinculó un controlador al evento 'restablecer' de su modelo persistente. Cuando luego reiniciemos ese modelo desde la línea de comando, veríamos tantos eventos desencadenados como casos de esa vista. En otras palabras, esa vista no se estaba recogiendo basura, a pesar de que los elementos que se agregaron al DOM se destruyeron por completo.

Nuestra solución fue simplemente asegurarnos de crear una instancia de nuestras vistas de nivel superior una vez, y luego hacer que establezcan sus vistas secundarias en sus métodos de inicialización. Luego solo vuelva a renderizarlos según sea necesario. Entonces no tiene que preocuparse por la complejidad de la recolección de basura (que, por lo que puedo decir de nuestros experimentos, no ocurre de todos modos).

+0

Bien, pregunta tonta: ¿Cómo pudiste ver cuántos eventos fueron despedidos? Nunca he sido capaz de resolver esto ... –

2

creo que los controladores de eventos DOM deberán ser eliminados mediante a) Método (llamada para eliminar de la vista - ver http://api.jquery.com/remove (que Backbone llama bajo las sábanas)

Si anula el método remove() para eliminar también vinculante para cualquier evento modelo como sugirió JohnnyO, la recolección de basura debería ocuparse de eliminar la vista.

que terminé haciendo reemplazando el método remove() para manejar esto:

class EmailView extends Backbone.View 
    initialize:() -> 
     @model.bind('change', @render) 
    render:() => 
     # do some stuff 
    remove:() -> 
     @model.unbind('change', @render) 
     super() 

A continuación, puede utilizar como tal en un Router:

routes: 
     'email/:id': email 

    //... 

    email: (id) -> 
     var email = new Email({ 
     id: id 
     }); 
     this.emailView.remove() if this.emailView 
     this.emailView = new EmailView({ 
     model: email 
     }); 
     email.fetch(); 
    } 

Esto funcionará si se asume que todos los eventos en la vista está vinculada al elemento correcto, es decir, que está utilizando @el (o this.el) en la Vista y que cada vista tiene su propia @ el/this.el.

Cuestiones relacionadas