1

I am using Angular to hide/show items of a unordered list. Since the effect is a bit too fast for the user to notice the disappearance/appearance of my lis, I want to add a transition on the height.

li {
  transition: height 1s linear;
  overflow: hidden;
}

li.ng-hide {
  height: 0;
}

This is where my problem is : the transition does not affect the lis, unless I set them a height, which I don't want, since I don't exactly know how big they are.

Here is a plunker to illustrate that. I've made the test on lis and divs and I've also tried without Angular which does not seem to be the responsible.

How can I make the transition work without setting the height of my elements ?

moudug
  • 209
  • 1
  • 3
  • 13

3 Answers3

1

I have come across the same problem myself in the past and discovered as you have that the height must be set, this is in order for the transition to calculate what needs to happen. Two ways I have managed to get round the problem:

CSS way:

li {
  transition: max-height 1s linear;
  overflow: hidden;
  max-height: 500px; // Any value above what you expect to be the biggest
}

li.ng-hide {
  max-height: 0;
}

The above method has a two drawbacks in that, one you'll need to know an upper limit and two there will be a slight jump in animation. A better way might be to calculate the height with javascript:

** UPDATE FROM JQUERY **

var listItems = document.getElementsByTagName("li")

for (var i = 0; i < listItems.length; i++) {
  listItems[i].style.height = listItems[i].clientHeight + 'px';
}

Then you'd need the css:

li.ng-hide {
  height: 0 !important;
}

To override the style attribute. Here is a pen of this example with a little bit extra in to illustrate the solution.

Ian Taylor
  • 357
  • 2
  • 14
  • Don't use jQuery in AngularJS. – lin Jun 08 '17 at 09:08
  • @lin I had overlooked the angular part and used jQuery as an easier to write solution. Have updated now. – Ian Taylor Jun 08 '17 at 09:27
  • If there is better solution why can't we use that rather than going to a complex part? – Mr_Perfect Jun 08 '17 at 09:29
  • 1
    @Mr_Perfect the vanilla javascript solution is still simple, I just meant for myself it's easier to write in jQuery as I'm more used to that. Have you tried both solutions? – Ian Taylor Jun 08 '17 at 09:31
  • @IanTaylor your script does the same as jQuery do -> DOM INJECTIONS. This is not how you should solve such things while using AngularJS. Its still the same problem like by using jQuery. `document.getElementsByTagName("li")` breaks if the element is not present in HTML while executing and it also breaks if the rendered element does change. Please make yourself understood how AngularJS E2E binding work. Don't provide such solutions for AngularJS applications. Or create a directive for it. I don't recommend to use this solution because it will break your AngularJS application. – lin Jun 08 '17 at 09:32
  • @IanTaylor please read this before providing such low quality answers: https://stackoverflow.com/questions/14994391/thinking-in-angularjs-if-i-have-a-jquery-background – lin Jun 08 '17 at 09:37
1

Just do it by animate max-height instead of height like in this DEMO PLNKR. In that way you are able to have a dynamic height of your element between 0 and your max-height property. There is no need for jQuery. You should avoid using jQuery or direct DOM-Injections in AngularJS applications.

li,
div {
  transition: all 1s linear;
  -webkit-transition: all 1s linear;
  border: 1px solid;
  overflow: hidden;
}

.work {
  border-color: green;
  max-height: 500px;
}

.no-work {
  border-color: red;
  max-height: 500px;
}

li.ng-hide,
div.ng-hide {
  max-height: 0;
}
lin
  • 17,956
  • 4
  • 59
  • 83
  • What if the height of the div is more than 250px? – Mr_Perfect Jun 08 '17 at 09:11
  • Just put it on `2000px` or somethink like that. This solution is the common way to handle your problem. Must important is to not use jQuery in a AngularJS application. – lin Jun 08 '17 at 09:11
  • Try put `20000px` in your plunker and check – Mr_Perfect Jun 08 '17 at 09:17
  • Yep, still working fine. The animation is just faster. See here: https://plnkr.co/edit/Ti19Co6yk5pZdyZXUHhL?p=preview – lin Jun 08 '17 at 09:19
  • I set this answer as selected, even though a delay is introduced at the beginning of the animation. Since I can determine roughly a not so exagerated max height, that trick does the job. Thanks. – moudug Jun 08 '17 at 10:04
0

You don't necessarily need to set your transition on height. You can set it on the ng-hide or ng-show property.

Here is your example with this feature :

https://plnkr.co/edit/pD4sQNGqpqrINJlZwE3q?p=preview

Simply assign the class to the element you want to animate.

.animate.ng-hide-add,
.animate.ng-hide-remove {
  transition: all linear 2s;
}

You'll find more infos here : https://docs.angularjs.org/api/ng/directive/ngShow

nb: You can seperate the animation for ng-hide-add and ng-hide-remove in your css. of course.

Hope it helps !

Louis Lecocq
  • 1,764
  • 3
  • 17
  • 38