Ember Animate View on Destroy


#1

Has anyone worked on animating a view when it being destroyed ?? this is the template code…
{{#if aVariable}} {{view aView}} {{/if}}

To fadeIn the view i hacked around and got a working solution.

App.aView = Ember.View.extend
    didInsertElement:()->
        id= @get('elementId')
        elem = $("##{elem}")  
        elem.hide()
        Ember.run.next @, ->
            elem.fadeIn(250)    

This nicely fades in the view after it has been inserted. I am trying to achieve the same kind of fadeOut transition when the element is being destroyed using the willDestroyElement event in the view. The problem is that willDestroyElement does not wait for the fadeOut to complete. So before the fadeOut transition begins the element is actually removed from the DOM.

App.aView = Ember.View.extend
    willDestroyElement:()->
        id= @get('elementId')
        elem = $("##{elem}")  
        elem.fadeOut(250)    

One solution would be if willDestroyElement implemented some kind of promise so that we can have async code in this function. I would like to know if any body has solved this problem.


#2

Here is one approach:

  willDestroyElement: function() {
    var clone = this.$().clone();
    this.$().parent().append(clone);
    clone.fadeOut();
  }

#3

thanks. worked like a charm !!


#4

Yea, thank you. But how would you implement this when only the model context changes? E.g. changing from one post to another post. To do it properly I really need the two posts in two different containers. Ideas for faking it?

Example jsbin.


#5

put an observer on the view that observes the context?


#6

Here is a little mixin that I wrote that handles both the cases … Initial fadeIn and fading the view in when the model changes.

App.ViewFader = Ember.Mixin.create
	fadeSelector:`undefined` #fade in a specific element instead of the entire view element.
	fadeOnModelChange:(->
		@rerender() #rerendering the view even if only model changes of the controller.
	).observes('controller.model')
	getElem:()->
	    if @get('fadeSelector')
                $("##{@get('elementId')}").find("#{@get('fadeSelector')}") 
            else 
                $("##{@get('elementId')}")
	
hideAndFade:()->
		elem=@getElem()
		elem.addClass("animated-fade fade-hidden")
		Ember.run.next @,->
			elem.removeClass("fade-hidden")
			elem.addClass("fade-shown")
	fadeMeOut:()->
		#this will take the cloned element of the view and fade it out. after fade out time
		#has passed we remove the element from the DOM.
		clone = @.$().clone()
		@.$().parent().append(clone)
		clone.removeClass("fade-shown")
		Ember.run.next ->
			clone.addClass("fade-hidden")
		Ember.run.later ->
			clone.remove()
		,200

This should deal with you case of when the model changes. One thing to note is that i call rerender() when the model changes. That I would say is not the Ember way of dealing with it but it works for me.

Here is the css

.animated-fade{
	transition:opacity $fade-time;
}

.fade-hidden{
	opacity: 0 !important;
}
.fade-shown{
	opacity: 1 !important;
}

Tweak the fade time to your requirement.