zurb / foundation-apps

The first front-end framework created for developing fully responsive web apps.
http://foundation.zurb.com/apps
MIT License
1.58k stars 216 forks source link

Synchronizing animations #674

Closed soumak77 closed 8 years ago

soumak77 commented 9 years ago

There are cases when I would like to sequence animations provided by F4A and want to know the best way to handle such cases. In my case, I require that the animation be definitely completed, so I can't rely on a timeout that fires after some duration as a race condition could cause the timeout to trigger before the animation is completed. I also don't want to have hardcoded animation delays in my code as that won't be manageable. I must ensure the animation is completed because I use the final positioning of the element in an operation I perform after the animation (i.e. move another element close to the animated element).

I was looking through the animation codebase and think the best way to achieve this is to have FoundationAnimation.animate return a promise, which resolves when the animation is completed or rejected when the animation is canceled. This is backwards compatible as currently FoundationAnimation.animate doesn't return a value meaning no existing code relies on the return value. FoundationAnimation.animate is just a wrapper for FoundationAnimation.animate and can be updated to return a promise for the same reasons.

Once FoundationAnimation.animate returns a promise, the F4A components can be updated to notify clients when an animation is completed. For example here is the current show method for panels:

scope.show = function() {
  if(!scope.active){
    scope.active = true;
    foundationApi.animate(element, scope.active, animationIn, animationOut);
  }

  return;
};

and here it is with the updated code

scope.show = function() {
  if(!scope.active){
    scope.active = true;

    foundationApi.animate(element, scope.active, animationIn, animationOut).then(function() {
      foundationApi.publish(attr.id, 'show-success');
    }, function() {
      foundationApi.publish(attr.id, 'show-error');
    }).finally(function() {
      foundationApi.publish(attr.id, 'show-complete');
    });
  }

  return;
};

A client can then subscribe for completion notifications for various animations and perform some action after it is complete. If they must only perform an operation if the animation was successful (which it should be in most cases), they can subscribe to only the success message.

soumak77 commented 9 years ago

BTW in terms of #536, here is a case where using the angular pub/sub would help as it also allows passing data, so we could just fire one event in the promise.finally block and pass along the success/error info instead of having to fire specific events for success/error

soumak77 commented 9 years ago

I made the changes necessary for my app in my forked repo: 84fe2e23ece29aa5a90283961af3f609d7b5210a

I realized that having a success/error for each action wasn't going to really help me do what I needed. Instead what I was really after was knowing the active state of an element once the animation was complete on that element. So I instead added two new messages active-true and active-false which are sent once the open/show animation is complete or the close/hide animation is complete, respectively. Let me know if you want me to work on a PR for integration of these changes.