There is currently no way to delay view destruction in Ember. This presents a problem when you want to animate the view before destroying it.
So, I currently have th
Try this
Ember.Route.extend({
actions: {
willTransition: function(transition) {
$.each(Ember.View.views, function(index, value) {
var popUpView = value.get('classNames').find(function(item) {
return item == '[nameofyourclass]';
});
if(!Em.isEmpty(popUpView) && value.get('visible')) {
value.set('visible', false);
value.get('controller').set('previousTransition', transition);
transition.abort();
}
});
return true;
},
}
});
Ember.View.extend({
classNames: ['nameofyourclass'],
classNameBindings: ['visible:element-visible'],
visible: false,
didInsertElement: function() {
var t = this,
controller = this.get('controller');
this.$()
.on('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function() {
if(!t.get('visible')) {
var previousTransition = controller.get('previousTransition');
if(!Em.isEmpty(previousTransition)) {
controller.set('previousTransition', null);
previousTransition.retry();
} else { // fallback
controller.transitionToRoute('index');
}
}
});
Em.run.next(this, function() {
this.set('visible', true);
});
},
});
This is just an spontaneous idea from my side:
This is the implementation of destroyElement in Ember.View (Link to Source):
destroyElement: function() {
return this.currentState.destroyElement(this);
},
You could try to override this method to do your animation:
destroyElement: function() {
var completeCallback = function(){
return this.currentState.destroyElement(this);
}
this.$().fadeOut(completeCallback); //or whatever animation
},
My preferred method for handling pre-destroy animation is using Em.Evented
. Have the view listen for an event that is called in the method or action that will start destruction of the view and delay the destruction until the method triggered by the event is complete (using the run loop). For example:
SomeView = Em.View.extend({
_listen: function() {
this.get('controller').on('closeChildView', this, this.hide);
}.on('willInsertElement'),
hide: function() {
this.$().fadeOut(this.get('controller.duration'));
}
});
And then in the controller:
Em.ObjectController.extend(
Em.Evented, { // Important mixin!
duration: 500,
actions: {
removeSomeChildView: function() {
this.trigger('closeChildView');
Em.run.later(this, function() {
// Then do the stuff to destroy the view here.
}, this.get('duration'));
}
}
});
Alternatively, you can use the this.removeFromParent()
method in the view to consolidate the hiding and removing of the view.
If the destruction is actually started in the view itself, you could use these same principles before you call the destroy method and use .on('willDestroyElement')
to send an action to the controller or route should you need a callback after the view has been removed.
Pre-destroy animation can be done in the same way by running this.$().hide
on didInsertElement
and then using a show()
method to transition the view element.
If you doing some of all of your transitions in CSS you'll want to make sure the transition times between the CSS and JS are aligned. This is pretty simple. In your view, make sure the CSS transition takes place on the view's element and then:
SomeView = Em.View.extend({
transitionDuration: Em.computed.alias('controller.transitionDuration'),
setTransitionDuration: function() {
var ms = parseFloat(this.$().css('transition-duration')) * 1000; // In milliseconds
if (ms) {
this.set('transitionTime', ms);
}
}.on('didInsertElement'),
});
This will update the transition duration on your view and controller to match whatever you write in your CSS. Whatever value you specify for transitionDuration
on the controller is the fallback value for transitionDuration
and you could add an if ()
in the above method should you want to do some validating before overriding the default JS transitionDuration
.