-1

I'm trying to creating a basic javascript animation with ngAnimate, but the event / animation doesn't fire when an element is added.

Essentially, I'm adding an element with a class test on click, which should change its color to green. But the color does not change and the alert doesn't fire. This is a basic example pulled from the tutorial so it should be working.

Any idea what could be going wrong?

html:

<body ng-controller="MainController as Ctrl">
   <h1>Hello Plunker!</h1>
   <span ng-click="Ctrl.append()">Add</span>
</body>

app.js:

var app = angular.module("myApp", ['ngAnimate']);

app.controller("MainController", function(){
  this.append = function(){
    var li = $('<li></li>').addClass('test').text("hey");
    $('body').append(li);
  };
});

app.animation(".test", function(){
   return {
    enter: function(element, done) {
      alert(element);
      console.log(element);
      $(element).css('color', 'green');
      done();
    },
    leave: function(element, done) { }
  };
});

Example in a plunker: http://plnkr.co/edit/alTUxFw4twL4LAaCDZvG?p=streamer

agconti
  • 17,780
  • 15
  • 80
  • 114
  • 1
    Did you seriously read a tutorial that recommended doing DOM manipulation inside a controller function, using jQuery and without doing a $compile of the new DOM elements? And how in the world do you expect angular to be aware of that? – Josep Sep 29 '14 at 16:28
  • @Josep appending the `li`s is only for this demo. I've reduced the feature in my app to this so it highlights the issue and is easier to answer. – agconti Sep 29 '14 at 17:15
  • 1
    As I have already explained in my answer doing that makes absolutely no sense in Angular. The controller is supposed to handle the model, the changes in the view are supposed to be done with directives that consume the model. What you are doing in your code is to use the directive for updating the view without changing the model or using directives, so Angular has no idea that that change just happened in the view. – Josep Sep 29 '14 at 17:22
  • @Josep I realized that ngAnimate needs a directive, like `ng-repeat` or `ng-view`, in order to fire. A succinct answer would have been just that. Your rant on wether my demo does things in the "Angular Way" is irrelevant and unproductive. – agconti Sep 29 '14 at 17:38
  • 1
    @agconti it's neither irrelevant nor unproductive. Your code is all kinds of wrong and therefore extremely hard to understand. By introducing DOM manipulation in the controller, there's no way I can guarantee that hasn't introduced one of numerous potential problems. – m59 Sep 29 '14 at 18:03
  • 2
    @agconti I agree with above comments, it is very valid to point out the issue in the posted code, and actually this should be done in angular way, you don't really deal with DOM when you are in the controller (there are exceptions when you use directive to achieve DOM manipulation but not definitely in this case though). – PSL Sep 29 '14 at 18:20
  • @PSL I don't think there is ever a case where we should manually traverse the DOM (perhaps I misunderstood you). The only way Angular code should ever get any DOM reference is via the injection provided by directives. Even a parent element would be associated by a directive on that parent, and so on, and the parent/child relationship can be established through a shared directive controller. – m59 Sep 29 '14 at 18:35
  • @m59 Not all features are data driven, unless the app is less ui intensive. Atleast with some of the components i have created for my projects.. You may need to build components that are heavily ui dependent and has nothing to do with data (an example where i had to do was while implementing a timeline and slider widget). You need to implement DOM manipulations and what not to achieve them. Well even if you look at the directives like angular ui or even the angular diretives that you use under the hoods they have DOM manipulations, so if you create something similar you would need to... – PSL Sep 29 '14 at 18:58
  • @m59, this code obviously doesn't reflect a real life application. Its just a bad demo. The point of it was to only to show an element entering. While information on how to do things the right way is always appreciated, the answer that solves this issue is lost and obscured with in all of that advice. My comment tried to highlight that, but clearly didnt do a good job. – agconti Sep 29 '14 at 19:01
  • @m59 contd... So my point was, if you are creating components/widgets out of the box (that are not readily available or a customized one to suit your application requirements) you would need to perform DOM manipulations in your custom directives... Hope this clarifies what i meant. – PSL Sep 29 '14 at 19:09
  • @PSL hmm, I guess I'd just need to run into it for myself. I haven't wrapped my head around that yet. @agconti, you're still not understanding that you just cannot do what you're doing there without issues - those new nodes are not even compiled with Angular, and therefore have absolutely nothing to do with the Angular application. You would have to call `$compile(elements)($scope)` before anything would happen. At that point, you're introducing even more complexity to the example than putting it in a directive where it belongs! – m59 Sep 29 '14 at 19:56
  • 1
    @agconti let me get this straight: you wanted to know why your ngAnimate wasn't firing, you provided a code that was wrong and the ultimate reason why your ngAnimate wasn't firing. I explained you why if you code according to the framework standards everything will work and I give you an example, then you complain saying things like "Your rant on wether my demo does things in the 'Angular Way' is irrelevant and unproductive". Then you get 2 Angular experts telling you that you're completely wrong and yet you still have the courage to insist that this answer is "is lost and obscured"?? o_O – Josep Sep 29 '14 at 22:52

1 Answers1

2

In Angular it makes absolutely no sense to do something like that, I've changed your code to make it work the way that I think that you wanted it to work but in an "Anular Way".

Please bare in mind that in Angular you should never do DOM manipulation from the Controller, DOM manipulation should only be done inside the directives. The controller is supposed to handle the model, the changes in the view are supposed to be done through directives that consume the model. What you are doing in your code is to use the directive for updating the DOM directly without changing the model or using directives, so Angular has no idea that that change just happened.

Now your controller looks like this:

app.controller("MainController", function($scope){
  $scope.messages = [];
  var cont = 0;
  this.append = function(){
    $scope.messages.push({id:cont++, text:'hi '});
  };
});

And your view looks like this:

  <body ng-controller="MainController as Ctrl">
    <h1>Hello Plunker!</h1>
     <ul class="example-animate-container">
      <li ng-repeat="message in messages" class="animate-repeat test">{{message.text}}</li>
    </ul>
    <span ng-click="Ctrl.append()">Add</span>
  </body>

Example

Also I would recommend you to have a look at this: "Thinking in AngularJS" if I have a jQuery background?

EDIT:

As per @PSL request I just added a few ng-repeat animations to the example.

The additions to the style.css:

.example-animate-container {
  background:white;
  border:1px solid black;
  list-style:none;
  margin:0;
  padding:0 10px;
}

.animate-repeat {
  line-height:40px;
  list-style:none;
  box-sizing:border-box;
}

.animate-repeat.ng-move,
.animate-repeat.ng-enter,
.animate-repeat.ng-leave {
  -webkit-transition:all linear 0.5s;
  transition:all linear 0.5s;
}

.animate-repeat.ng-leave.ng-leave-active,
.animate-repeat.ng-move,
.animate-repeat.ng-enter {
  opacity:0;
  max-height:0;
}

.animate-repeat.ng-leave,
.animate-repeat.ng-move.ng-move-active,
.animate-repeat.ng-enter.ng-enter-active {
  opacity:1;
  max-height:40px;
}
Community
  • 1
  • 1
Josep
  • 12,926
  • 2
  • 42
  • 45
  • This answer could be definitely be improved with the specifics of what makes ngAnimate fire. – agconti Sep 29 '14 at 19:03
  • 2
    @agconti You can actually refer to official documentation or even debug ngAnimate code to clearly understand how it works... – PSL Sep 29 '14 at 19:11