PrimeLens
PrimeLens

Reputation: 2727

How can angular listen event for css transition end where ng-style triggers the transition

I had to add some jQuery to the end of the code just to detect when a css transition ends. Is there a way to have angular do this?

working jsfiddle is here

The way it works is to have an object that contains top and left coords which is injected as an inline style by ng-style.

Several of these objects are kept in an array. Whenever the css3 end transition event is detected the next object gets injected.

Here is the HTML with Angular directives.

 <div id="mycontainer" ng-controller="mycontroller">
   <div ng-repeat="item in mylist" id="item{{item.key}}" class="item" ng-style="myproperties({{item.key}})">{{item.value}}</div>
 </div>
 <div id="readout"></div>

Here is the Javascript / Angular, you will see the jQuery, really obviously added near the end.

var myapp = angular.module('myapp', []);
myapp.controller(
  'mycontroller', 
  [
    '$scope',
    '$log',
    function($scope, $log) {
      // define the items
      $scope.mylist = [];
      for (var i = 0; i < 6; i++) {
        $scope.mylist[i] = {'key':i, 'value':i, 'inlinestyle':{'top':'60px','left': (i*60)+'px'}};
      }

      $scope.myproperties = function(arg) {
              return $scope.mylist[arg].inlinestyle;
      };

      /*  test animatimng item number 2 */

      var anime = [
        {'top':'120px','left':'50px', 'background':'#ccc'},
        {'top':'150px','left':'120px', 'background':'#3cc'},
        {'top':'60px','left':'120px', 'background':'#c3c'},
        {'top':'120px','left':'130px', 'background':'#cc3'},
        {'top':'150px','left':'160px', 'background':'#fff'}
      ];
      var playhead = 0;
      var saveTimeStamp = 0;

      // adter a second, start the anime sequence
      setTimeout(function(){
        $scope.mylist[2].inlinestyle = anime[0];              
        $scope.$apply();
        playhead++;       
      }, 1000);

      //listener for end of transition
      // aaaah ...  now I have to use jQuery
      $('html').on('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function(e){
        if (( e.timeStamp != saveTimeStamp ) && (anime[playhead])  )  {
          $('#readout').append('ended '+playhead+' '+JSON.stringify(anime[playhead])+'<br>');
          saveTimeStamp = e.timeStamp;            
          $scope.mylist[2].inlinestyle = anime[playhead];              
          $scope.$apply();
          playhead++;
        }                
      });

    }
  ]
);

Upvotes: 4

Views: 4517

Answers (1)

makeroo
makeroo

Reputation: 527

Angular way is to define a directive.

I followed this blog post: https://jonsuh.com/blog/detect-the-end-of-css-animations-and-transitions-with-javascript/ and trasformed that code in a angular directive like this:

 myapp.directive('myTransitionEnd', [
           '$parse',
 function ( $parse  ) {
    var transitions = {
        "transition"      : "transitionend",
        "OTransition"     : "oTransitionEnd",
        "MozTransition"   : "transitionend",
        "WebkitTransition": "webkitTransitionEnd"
    };

    var whichTransitionEvent = function () {
        var t,
            el = document.createElement("fakeelement");

        for (t in transitions) {
            if (el.style[t] !== undefined){
                return transitions[t];
            }
        }
    };

    var transitionEvent = whichTransitionEvent();

    return {
        'restrict': 'A',
        'link': function (scope, element, attrs) {
            var expr = attrs['myTransitionEnd'];
            var fn = $parse(expr);

            element.bind(transitionEvent, function (evt) {
                console.log('got a css transition event', evt);

                var phase = scope.$root.$$phase;

                if (phase === '$apply' || phase === '$digest') {
                    fn();
                } else {
                    scope.$apply(fn);
                }
            });
        },
    };
 }]);

then, change your html like this:

<div id="mycontainer" ng-controller="mycontroller" my-transition-end="callSomeScopeFunctionYouDefined()">

Upvotes: 4

Related Questions