Animation support in Ember 1.1

@seilund it is just if you want something complex enough, you won’t be setting one property but you will have to queue a few transitions (a few setters)

Just checked it out. Those issues do not seem unsolvable to me. But we’re talking very low-level here. Let’s get back to that later when we get enough feedback on the public API and how people are going to use it. I’ll definitely let you know as you seem to have some valuable experience here too :slight_smile:

Check out the “Chaining & queuing” example on Transit - CSS transitions and transformations for jQuery. Unless it has bad performance on mobile I think this is a good solution, since developers can easily implement their own crazy effects.

For reference this seems to be a quite good comparison of transitions VS animations

Interesting article. I don’t find anything about performance though?

I am worried about performance because it seems to me that with transitions we are going to do more work in js then with animations that’s all. But you right lets see how it goes. After all as long as we have the right hooks, how the animation is implemented is only a detail.

Exactly :slight_smile:

JS should only kickstart the animation by setting some css transition properties (and that’s what jQuery.transit does to the best of my knowledge).

Very happy that you’ll be digging into this.

I have scattered thoughts about this; toward the end I’ll try to coalesce them into some more general patterns/considerations:

  • What happens when the user clicks on buttons during transitions?
  • What happens when the user navigates (clicks the back/forward buttons) during a transition?
  • How would you handle something like the (now out of date) github source tree drilldown transition, where you click a directory, and the current level slides left out of view, puts up a spinner while waiting for the drilldown data to come back from the server, and then the new frame comes in?
  • Furthermore, as much as you might support a wildcard route path that facilitates a filesystem-resembling URL scheme, this Github transition example is really just an example of when you’re on FolderShowRoute and switching between models represented by the URLs (e.g.) “/foo” and “/foo/bar”. Perhaps this is more of an implementation consideration, but this is an example of when you’ll have 2 FolderShowViews on the screen at the same time, one for the outgoing “/foo” and one from the incoming “/foo/bar”. Is such a thing supported given your present thoughts?

I’ll have more later, just curious about these for now. In short, these basically make me think these animations ought to be more state-ful, so that you can intelligently handle events fired and now have to handle, in multiple routes, logic pertaining to if(isTransitioning/animating).

Great questions.

Maybe nothing special. I propose in this first iteration that only one animated transition can happen at the same time. If another transition is requested while animation is being performed, the transition is queued (like I mentioned in “Transition flow” #1. See also “Known limitations” #2. Same with back/forward buttons: The transition is simply queued.

I believe (maybe I’m wrong) that the GitHub file tree only slid once: User clicks, file tree slides to the left, animation spinner is sliding in from the right, once new files are loaded the spinner is replaced with real content (no second slide effect). You could solve that using a {{#if model.files.isLoaded}} in your template. If you want to have two slide animations, like you describe it, this is a way to do it (using sub-states as we talked about in Is there a reason we can not have nested routes? - #16 by machty):

App.Router.map(function() {
  this.resource('tree', '/tree/:node_id', function() {
    this.state('loading'); //New API that we will hopefully get
  });
});

//Represents a file/directory
App.Node = DS.Model.extend({
  name: DS.attr('string'),
  children: DS.hasMany('App.Node')
});

App.TreeIndexRoute = Ember.Route.extend({
  model: function() {
    return this.modelFor('tree').get('nodes'); //Should be a thenable
  }
});

App.TreeIndexController = Ember.ObjectController.extend({
  didClickNode: function(node) {
    var self = this;
    this.transitionTo('tree.loading', node).then(function() {
      self.replaceWith('tree.index');
    });
  }
});

tree/loading.hbs would show the spinner. tree/index.hbs would show the file list and have {{action didClickNode node}} for each file. Since they are “sub-states” the URL would not change (which makes sure that a deep-link will never take a user to a loading state). It doesn’t matter how long time the files are to load, the app will transition to tree.index once both the first animation has completed and the child nodes has been loaded (since we’re returning a promise in App.TreeIndexRoute’s model method. A Transition should be resolved as soon as animation starts, which will enqueue the next animation. This is actually a perfect example of when sub-states would be awesome to work with.

Do you mean if it’s supported to have two instances of the same route’s view on screen at the same time? Not currently, but that will have to be changed to support animated transition from and to the same route with a different model.

Please say more :). I like the thought that they ought to be more stateful. Imagine if the animation effect was a class instead of a plain function. That way it could have a stop hook and other “stateful operations”. Example:

Ember.SlideLeftEffect = Ember.Effect.extend({
  animate: function() {
    this.get('newView').$().transition({...}, this.done);
  },

  stop: function() {
    this.get('newView').$().stop();
    this.done();
  }
});

Effect names could also be looked up through the container in this example. E.g. container.lookup('effect:slideLeft'). I actually like the effects as classes better.

I read this from a link on Twitter. I’m not currently an Ember user so when I was reading this I, and the 5 people who interacted with my tweets about it misunderstood this spec. To me this spec reads as if Ember will be doing all the animations. This can be off-putting to people looking into frameworks because they see this as monolithic. “Why does Ember also do animations?”.

There’s only one line that makes it clear Ember wont be handling the animations. The rest is filled with text like:

  • “built-in animation support”
  • “Ember should ship with its own standard effects.”
  • etc.

My only suggestion is to make it clear Ember is not doing any animation and instead explain up front what it IS doing. @trek explained it’s just adding a class which is a lot more reasonable. From someone looking at this as a potential framework choice they might not get that.

Good luck!

I agree with everyone suggesting we don’t want to get into the business of handling the actual implementation specifics of the animation. Things like duration, timing, etc are, IMO, like CSS: design decisions left up to the developer.

The future of animation does seem to be applying css classes. Not sure how we’d let Ember know how long each animation lasts, though.

I’m also open, personally, to the idea of making animations a progressive enhancement for modern browers.

I like the idea of a transition effect being a class looked up through the container as @seilund describes. That way the implementation specifics can be whatever an individual requires, whether that’s adding a css class, or jQuery transition, or using one of the libraries mentioned.

The Ember starter kit can then come with some example css transitions, and there could be other projects which build on that, like ember-cpm does for computed property macros.

Why? Then you wouldn’t be able to make just one view different from the other ones if you are setting an effect as default (outlet). @xeppelin is right. The view effect should take precedence over the outlet. But I guess it would be better to set the effect in the route if you want to be specific:

App.FooRoute = Ember.Route.extend({
  transitionIn: 'slideUp'
});

Mainly because I don’t see the ES6 HTMLElement doing that in the future. And we should keep things between HTMLElement and Ember.View as close as possible. {{outset}} is more close to Ember.Route than Ember.View in this matter too.

I’d like to provide an example of the last app I wrote’s animations, since it provides edge cases for animation cases involving lists. Animations should not be state-less. That is my opinion. There is possible forking and situational transitions depending on any number of states.

For the app that I’m showing, it has contextual animations depending on whether the user is removing groups, whether they are changing the sort, and whether a user’s status has caused them to change groups. This is intuitive, but the code to make it work is damnably complicated.

I would love for ember to handle these cases with aplomb, but I know it’s asking for a lot. Also, I think we should look at what people would like to do with animations rather than just tacking on animation support. Understanding why and how animations are used will result in a much better API than simply jamming the animation on an outlet (which is IMO, really awesome in a good number of cases)

Here’s all the gifs: :smile:

Grouping / ungrouping:

Status changes:

Sorting:

Searching:

Removing contacts:

Detail Cards:

Changing app views:

3 Likes

I agree with @guilhermeaiolfi. No transition property on views, only on routes. And routes take precedence over {{outlet}}, because when you define it on the route it’s a special case.

@seilund Meaning a view can only have animation when defined on a route? What about views created with {{view App.MyView}}, {{my-control}}?
The only way having them animated is supposed to be doing it manually in view lifecycle hooks?

@seilund thanks for starting the discourse on this - as a developer of mobile apps using Ember, this is super important.

From a quick peek at the Angular code I believe they determine animation/transition length by parsing the computed style added by the transition classes.

Handling transitions can be fraught with state issues that may make it hard for Ember to stay out of some of the details. For example, what happens when a user hits the back button during a transition?

FWIW ContainerView hooks as proposed by @tchak in Ember PR #1539 can get you pretty far without Ember knowing anything about the concept of transitions.

First I want to say that I am very excited about animation support, this is totally something we should provide, and I want it to succeed.

But I have some concerns, I feel that this proposal currently scenario solves animations for when animations are related to the “node” being animated, but in practice it seems that it has more to do with the edge(s) traversed.

For reference, Reveal.js and Impress.js provide some interesting examples.

I can imagine a path where the above described DSL, or a variation of it, provides hints to a more flexible sub-system.

We have to be mindful about sending users down what appears to be an easy path, but as there app scales or needs change, they are forced to entirely revisit.

1 Like

I’m a little confused what problem is being solved by this proposal. I agree there is a problem, but this solution attempts to dictate too much to the developer. I don’t want Ember touching (or caring about) my styles. Ever.

Truthfully, it seems like the problem proposed is a marketing problem. I love Ember because it has very carefully regulated which problems it attempts to solve. Sometimes that makes it less flashy than other libraries from a very high level…but that’s entirely beside the point.

I use animations / transitions very liberally in my applications and the only real problem I have is that I don’t get to tell Ember when it’s okay to remove a view from the DOM. Some nice to haves would include built in handling for transition and animation events in the view (animationEnd and transitionEnd, for example).

If I’m understanding it correctly, @tchak 's solution seems create the tools I need to do this and doesn’t seem terribly complicated.

It seems that people are eager to discuss internal view lifecycle hooks as well. Awesome! Let’s move this part of the discussion here: Internal view lifecycle hooks for animation purposes

The original purpose of this thread was to talk about how route animations should be supported. Let’s continue with that here.

Great input. I just had a chat with @krisselden. We talked about letting the router keep its own internal history stack, which should store the animation effects it has performed to get to the current state. When user hits the browser’s back button, we will know which animation to perform by taking the “opposite” effect. Example: Look at The HTML presentation framework | reveal.js. Imagine that the up arrow in the lower right was constructed like `{{linkTo “page” upPage transition=“slideDown”}}. When user clicks the up arrow the next page slides down from the top. When the user hits the back button we know that we performed a slideDown to get there, so we will perform a slideUp to go back.

Thanks a lot for your input. You don’t have to use animated route transitions. You can hook into the upcoming view lifecycle hooks and do it however you want. That’s where we want to go: Giving us the power to manually customize when it’s okay to remove a view.

1 Like