2012-09-16 13 views
10

Estoy tratando de establecer animaciones en la representación y el cierre de un ItemView con Backbone.Marionette. Para renderizar una vista, esto es bastante simple:Backbone.Marionette: Defer view close until beforeCerrar animación se completó

MyItemView = Backbone.Marionette.View.extend({ 
    ... 
    onRender: function() { 
    this.$el.hide().fadeIn(); 
    } 
    ... 
}); 

Esto hará que mi vista se desvanezca cuando la renderice. Pero digamos que quiero desvanecer mi vista al cerrar.

beforeClose: function() { 
    this.$el.fadeOut();  // doesn't do anything.... 
} 

Esto no va a funcionar, porque el artículo se cierra inmediatamente después de llamar this.beforeClose(), por lo que la animación no tiene tiempo para completar.

¿Hay alguna manera, utilizando Marionette tal como está, para realizar una animación de cierre?


Por otra parte, esta es la solución que he estado usando:

_.extend(Backbone.Marionette.ItemView.prototype, { 
    close: function(callback) { 

     if (this.beforeClose) { 

      // if beforeClose returns false, wait for beforeClose to resolve before closing 
      // Before close calls `run` parameter to continue with closing element 
      var dfd = $.Deferred(), run = dfd.resolve, self = this; 
      if(this.beforeClose(run) === false) { 
       dfd.done(function() { 
        self._closeView();    // call _closeView, making sure our context is still `this` 
       }); 
       return true; 
      } 
     } 

     // Run close immediately if beforeClose does not return false 
     this._closeView(); 
    }, 

// The standard ItemView.close method. 
    _closeView: function() { 
     this.remove(); 

     if (this.onClose) { this.onClose(); } 
     this.trigger('close'); 
     this.unbindAll(); 
     this.unbind();  
    } 
}); 

ahora que puedo hacer esto:

beforeClose: function(run) { 
    this.$el.fadeOut(run);  // continue closing view after fadeOut is complete 
    return false; 
}, 

Soy nuevo en el uso de marionetas, así que No estoy seguro de si esta es la mejor solución. Si esta es la mejor manera, enviaré una solicitud de extracción, aunque querré pensar un poco más en cómo esto podría funcionar con otros tipos de vistas.

Esto podría ser utilizado para otros fines, como solicitar la confirmación al cerrar (vea este issue), o ejecutar cualquier tipo de solicitud asincrónica.

¿Pensamientos?

Respuesta

18

Sustitución del método close es la única manera de hacer esto, pero se puede escribir poco más corto, como se puede llamar a las marionetas close método en lugar de duplicarla:

_.extend(Backbone.Marionette.ItemView.prototype, { 
    close: function(callback) { 
     var close = Backbone.Marionette.Region.prototype.close; 
     if (this.beforeClose) { 

      // if beforeClose returns false, wait for beforeClose to resolve before closing 
      // Before close calls `run` parameter to continue with closing element 
      var dfd = $.Deferred(), run = dfd.resolve, self = this; 
      if(this.beforeClose(run) === false) { 
       dfd.done(function() { 
        close.call(self); 
       }); 
       return true; 
      } 
     } 

     // Run close immediately if beforeClose does not return false 
     close.call(this); 
    }, 


}); 

Otra idea es overide la remove método de su vista. Entonces se desvanece el elemento de la vista y luego lo elimina del DOM

remove: function(){ 
    this.$el.fadeOut(function(){ 
    $(this).remove(); 
    }); 
} 
+0

Ah ... gracias! Sabía que debe haber una manera más simple, y sobrescribir View.remove me parece más simple. Por cierto, en la devolución de llamada fadeOut, tendrá que llamar a '$ (this) .remove()', o 'Backbone.Marionette.ItemView.prototype.call (self)' – eschwartz

+0

Sobrescribir la función de eliminación es una solución mejor que anulando el método de cierre. Eso funcionó bien para mí. Gracias. – earl3s

Cuestiones relacionadas