Open bencbradshaw opened 6 years ago
Possibly related... I'm seeing something similar where the expansion panel is visible in a dialog as the dialog animates open. So it may appear that the animation does not have to applied directly to the expansion panel to see this behavior.
I have created an example for a router transition which illustrates the same problem:
Any updates on this? I thought maybe I had to specify something in my transition animations to cause everything to trigger in the right order, but if that's the case, I can't figure out what. I'd like to see an example of transitions that don't cause this behavior, if anybody has it working.
@aeslinger0
Possibly related... I'm seeing something similar where the expansion panel is visible in a dialog as the dialog animates open. So it may appear that the animation does not have to applied directly to the expansion panel to see this behavior.
See #13870. I am not sure they are related either, but what you describe seems similar to that issue.
That sounds likely, yeah. For now I have a workaround in my global styles. I'll keep an eye out for the linked patch landing and see if that fixes things.
That sounds likely, yeah. For now I have a workaround in my global styles. I'll keep an eye out for the linked patch landing and see if that fixes things.
Can you please tell how you fixed it? I partially fixed it in my code by to putting the content of expansion-panel to ng-template and fortunately it helped with collapsing it during transition animation, but instead that behavior, now initial size of expansion-panel is smaller then it should be (i believe because it contains totally nothing), but after animation it became normal.
I happen to only have this problem when a custom component, that contains a mat-card
with a few mat-expansion-panel
s on it, slides into view with an enter-animation. So, I made these rules:
.ng-animating mat-card mat-expansion-panel-header {
height: 48px;
}
.ng-animating mat-card div.mat-expansion-panel-content {
height: 0px;
visibility: hidden;
}
The expansion panel header, in its closed state, is normally 48px. If you don't force it to this height during the animation, but try to remove the expansion panel content DIV by settings its height to 0, it renders at the height of its content instead (the panel-title element, probably) then jumps to the 48px height after the animation completes.
Hope this helps!
.ng-animating mat-card mat-expansion-panel-header { height: 48px; } .ng-animating mat-card div.mat-expansion-panel-content { height: 0px; visibility: hidden; }
With little changes it works, thanks) And you are right, I have the same situation, with a little bit different HTML structure: custom component with expansion-panel inside and during enter-animation it is opened by default. If I put content of each panel in ng-content (to make it lazy-loaded) then content become invisible but height of the panel become too small. Only sad thing in my case, to make it work it requires to put these styles rules in the the global styles.css. When I put them in the specific component style sheet, the first rule (for header) applies perfectly but the second (for content) just doesn't work. Also I found that all these behavior worked fine even without hacks before I updated ng-material and angular libraries from version 6 to 7.
I think for your second rule you'd need a piercing selector, e.g. .ng-animating mat-card ::ng-deep div.mat-expansion-panel-content
-- the mat-expansion-panel-content
is part of the mat-expansion-panel
component so you can't style it without the ::ng-deep
. I find it easier to make the fix globally.
Piercing selector helped a lot:
::ng-deep .ng-animating div mat-accordion mat-expansion-panel mat-expansion-panel-header {
height: 48px;
}
::ng-deep .ng-animating div mat-accordion mat-expansion-panel div.mat-expansion-panel-content {
height: 0px;
visibility: hidden;
}
To say the truth, I totally forgot that styles are encapsulated by default in components not only from child to parent but also in opposite way. Thanks)
Hi every body, have you got some news about this issue ? Do you know if this fix will be integrated soon ? Thanks a lot!
I solved it temporarily until a fix arrives via a global style in style.scss:
// temporary fix for expansion panels until Angular Material Issue is fixed,
// see https://github.com/angular/material2/issues/13870
mat-accordion mat-expansion-panel {
mat-expansion-panel-header {
height: 40px; // height may be different for you
}
.mat-expansion-panel-content {
height: 0;
}
&.mat-expanded {
mat-expansion-panel-header {
height: 64px; // height may be different for you
}
.mat-expansion-panel-content {
height: auto;
}
}
}
So are Angular animations fundamentally broken if we get issues like this?
To visualize at least what's going on I found it helpful to add the following to global styles:
.ng-animating
{
outline: 1px solid red;
}
During a simple slide-in animation, the view of my accordion is like this:
So the .ng-animating
class is being inherited by the children of accordion and anything that is possible to be animatable is being highlighted as such. This happens even if my accordion is in a completely separate component of its own.
I've concluded the only way to get on with my day right now - is to just disable animations completely on the accordion.
<mat-accordion [@.disabled]="true">
None of the css solutions worked for me. The problem being they won't work for animating an accordion offscreen when you quite likely do want the panel to remain open in its current state. In addition if I click on an accordion that initially animates on screen (with a 30s animation) then I can't open any panels once the animation is complete. That seems like a much more serious issue, which I don't even understand.
In any case the problem seems to be that the .ng-animate
class is being inherited by the accordion control.
If there's no way to prevent this then surely animations are broken, and the fix needs to be of broader scope than a nasty css hack?
I solved it temporarily until a fix arrives via a global style in style.scss:
// temporary fix for expansion panels until Angular Material Issue is fixed, // see https://github.com/angular/material2/issues/13870 mat-accordion mat-expansion-panel { mat-expansion-panel-header { height: 40px; // height may be different for you } .mat-expansion-panel-content { height: 0; } &.mat-expanded { mat-expansion-panel-header { height: 64px; // height may be different for you } .mat-expansion-panel-content { height: auto; } } }
it solves the problem but it causes mat-panel content to jump for a while :(
Я решил это временно, пока не пришло исправление с помощью глобального стиля в style.scss:
// temporary fix for expansion panels until Angular Material Issue is fixed, // see https://github.com/angular/material2/issues/13870 mat-accordion mat-expansion-panel { mat-expansion-panel-header { height: 40px; // height may be different for you } .mat-expansion-panel-content { height: 0; } &.mat-expanded { mat-expansion-panel-header { height: 64px; // height may be different for you } .mat-expansion-panel-content { height: auto; } } }
это решает проблему, но некоторое время заставляет содержимое панели мата прыгать :(
I think that if you set these options to mat-expansion-panel-header, the jump in the content of the mat panel will be fixed. Replace with your height. <mat-expansion-panel-header [collapsedHeight]="'66px'" [expandedHeight]="'66px'">
I wanted to add another repro that may be illustrative
https://stackblitz.com/edit/sidenav-accordion-expansion
Here an accordion is in a component which is factoried at runtime into a sidenav; you can see the accordion is expanded during sidenav enter.
I applied my fixes from upthread and it resolves your issue. In styles.scss
, just add
mat-sidenav.ng-animating {
mat-expansion-panel-header {
height: 48px;
}
div.mat-expansion-panel-content {
height: 0px;
visibility: hidden;
}
}
Of course this should work out of the box, but you can use it as an interim fix.
Finally solved this by using these attributes
<mat-expansion-panel-header expandedHeight="46px" collapsedHeight="46px"> your text </mat-expansion-panel-header>
you can change the height as per requirement
TY me LATER :) ;) ;p
So are Angular animations fundamentally broken if we get issues like this?
To visualize at least what's going on I found it helpful to add the following to global styles:
.ng-animating { outline: 1px solid red; }
During a simple slide-in animation, the view of my accordion is like this:
So the
.ng-animating
class is being inherited by the children of accordion and anything that is possible to be animatable is being highlighted as such. This happens even if my accordion is in a completely separate component of its own.I've concluded the only way to get on with my day right now - is to just disable animations completely on the accordion.
<mat-accordion [@.disabled]="true">
None of the css solutions worked for me. The problem being they won't work for animating an accordion offscreen when you quite likely do want the panel to remain open in its current state. In addition if I click on an accordion that initially animates on screen (with a 30s animation) then I can't open any panels once the animation is complete. That seems like a much more serious issue, which I don't even understand.
In any case the problem seems to be that the
.ng-animate
class is being inherited by the accordion control.If there's no way to prevent this then surely animations are broken, and the fix needs to be of broader scope than a nasty css hack?
I was able to implement it with your approach of disabling animations instead this css's workarounds, but added a little twist , I instead setting the animations fully off I binded that field [@.disabled]
with a variable from my component that would be true by default but on click that that opens my ng-template via a Mat-Dialog I change the variable value after a timeout fixing the visual bug of the animation and allowing animations for the mat-expansion-panel like so:
this.dialog.open(accountRef).afterClosed().subscribe(() => { this.disableAnimations = true; }); setTimeout(() => { this.disableAnimations = false; });
And on my html
<mat-accordion [multi]="true" [@.disabled]="disableAnimations">
Just make sure to turn disableAnimations to true when this accordion leaves the screen so it fixes the next time the mat-expansion-panel shows on the screen, for me this accordion is inside a mat dialog so i achieved this with the afterClosed event
Having this issue when expansion panel is used in a mat-dialog. Expands for a second when dialog is opened.
any updates?
The only workaround that worked for me is:
<mat-accordion [@.disabled]="true">
Thanks @chipicow
So are Angular animations fundamentally broken if we get issues like this? To visualize at least what's going on I found it helpful to add the following to global styles:
.ng-animating { outline: 1px solid red; }
During a simple slide-in animation, the view of my accordion is like this: So the
.ng-animating
class is being inherited by the children of accordion and anything that is possible to be animatable is being highlighted as such. This happens even if my accordion is in a completely separate component of its own. I've concluded the only way to get on with my day right now - is to just disable animations completely on the accordion.<mat-accordion [@.disabled]="true">
None of the css solutions worked for me. The problem being they won't work for animating an accordion offscreen when you quite likely do want the panel to remain open in its current state. In addition if I click on an accordion that initially animates on screen (with a 30s animation) then I can't open any panels once the animation is complete. That seems like a much more serious issue, which I don't even understand. In any case the problem seems to be that the
.ng-animate
class is being inherited by the accordion control. If there's no way to prevent this then surely animations are broken, and the fix needs to be of broader scope than a nasty css hack?I was able to implement it with your approach of disabling animations instead this css's workarounds, but added a little twist , I instead setting the animations fully off I binded that field
[@.disabled]
with a variable from my component that would be true by default but on click that that opens my ng-template via a Mat-Dialog I change the variable value after a timeout fixing the visual bug of the animation and allowing animations for the mat-expansion-panel like so:
this.dialog.open(accountRef).afterClosed().subscribe(() => { this.disableAnimations = true; }); setTimeout(() => { this.disableAnimations = false; });
And on my html
<mat-accordion [multi]="true" [@.disabled]="disableAnimations">
Just make sure to turn disableAnimations to true when this accordion leaves the screen so it fixes the next time the mat-expansion-panel shows on the screen, for me this accordion is inside a mat dialog so i achieved this with the afterClosed event
this worked for me, but I insted of the timeout I used
ngAfterViewChecked(): void {
this.disableAnimations = false;
}
@ALGDB Angular will throw you the error NG0100: ExpressionChangedAfterItHasBeenCheckedError
if you perform changes directly after a check.
A possible solution is to queue the operation to the next change detection check like this:
ngAfterViewChecked(): void {
setTimeout(() => {
this.disableAnimations = false;
}, 0)
}
A more detailed explanation and different solutions can be found here in this video from the Angular docs.
I solved only this
::ng-deep .ng-animating mat-accordion mat-expansion-panel div.mat-expansion-panel-content {
height: 0px;
visibility: hidden;
}
I've found another workaround that might help a few people. See my comment here.
I have also fixed using:
.ng-animating .mat-accordion .mat-expansion-panel .mat-expansion-panel-content {
height: 0px;
visibility: hidden;
}
similar to above, works for me:
.mat-expansion-panel .mat-expansion-panel-content {
&.ng-animating {
height: 0;
}
}
Changing
query(':enter', animateChild(), { optional: true })
to
query(':enter', query('@*', animateChild(), { optional: true }), { optional: true })
fixed my issues.
Also ran into this issue today, and stumbled into a solution that seems to fix my issues.
Dependencies:
"@angular/core": "16.2.0",
"@angular/material": "16.2.4",
Two router animations
Slide/Swipe when navigating from any page to any other page.
<mat-expansion-panel [expanded]="false"
on the target page.
All components use OnPush
change detection.
For both situations the expansion panel starts as expanded, the page fades/slides in, then a moment later the expansion panel closes. I also sometimes have to click the header twice to get the panel to expand.
I tried some of the solutions given above, with [@.disabled]="true"
being the simplest fix for me, but I was left unsatisfied as it all felt like work-arounds for whatever the root problems was, and I was hoping for a solution that only changed the animation sequence/config.
After spending some time debugging in and out of the animation code and the components, I came to the conclusion that Angular wasn't animating the components on-page until some time after the router animation had finished. In other words the animation triggers were not getting triggered until the page was done animating and what appeared to be a new change detection cycle had started.
This is obviously undesired, but even more concerning is this doesn't match my expectations, as I have an animateChild()
query at the very end of my sequence that I expected to link up the child animations with the route animation.
transition('* => *', [
// Prep for animation
group([
query(':enter', style(...), { optional: true }),
query(':leave', style(...), { optional: true }),
]),
// Slide in
group([
query(':enter', animate(...), { optional: true }),
query(':leave', animate(...), { optional: true }),
]),
// Animate children
query(':enter', animateChild(), { optional: true }),
]);
I admit I know very little about Angular animations, this is the first project I have used them, so I thought if I moved the animateChild()
higher up in the sequence it would do all the on-page animations first, then slide the page in.
However, no matter where I put the animateChild()
the results were the same. Even if it was the first element in the sequence, the animations on-page always ran some time after the route animation had finished.
What stood out to me at this point was the Child
of animateChild()
, I had assumed that it animated all descendants not just direct children. Maybe that was a bad assumption?
I didn't find anything like animateChildRecursive()
or animateDescendants()
.
So, is there a way I can target all descendants?
A quick read of the query
function, I spotted some potential candidates
`query(":animating")` : Query all currently animating elements.
`query("@*")` : Query all elements that contain an animation triggers.
I tried with query(":animating")
and got the same results as before, so I tried query("@*")
and unexpectedly everything worked!
In the end my animation sequence ended up being
transition('* => *', [
// Prep for animation
group([
query(':enter', style(...), { optional: true }),
query(':leave', style(...), { optional: true }),
]),
// Slide in
group([
query(':enter', animate(...), { optional: true }),
query(':leave', animate(...), { optional: true }),
]),
// Animate :enter descendants
query(':enter', query('@*', animateChild(), { optional: true }), { optional: true }),
]);
I think query(':enter', query('@*'
is targeting all descendants of the page entering and animating them.
I still had the .ng-animating
red border @simeyla suggested from before, and with the fix, the expansion panel no longer has a red border while the page is sliding in.
While this did fix all the issues I was having, I still don't fully understand why it fixed them. It seems like Angular was not animating the full descendant tree with animateChild()
and I don't know if that was my fault or just a bad expectation.
I hope this helps someone else having similar issues, but I will say I don't know the full scope of the @*
selector so it is entirely possible this will trigger animations deep in the page undesirably.
My remaining unanswered questions are
query(':enter', animateChild()
doesn't seem to make it all the way down to the elements on the page.
query(':enter', query('@*'
as the last step in the route animation fix the problem?
Bug, feature request, or proposal:
Bug
What is the expected behavior?
Mat-expansion-panel, when animating in or out, will stay in current state of opened or closed and render as such.
What is the current behavior?
mat-expansion-panel, when animating out, will open and display all hidden panel content, while still showing the current state as closed.
What are the steps to reproduce?
https://stackblitz.com/edit/angular-ykxmcr?file=src%2Fapp%2Fhero-list-multistep.component.ts
What is the use-case or motivation for changing an existing behavior?
Keeping the panel closed when animating out provides a much cleaner experience for the UI by preventing jumpiness and inconsistencies.
Which versions of Angular, Material, OS, TypeScript, browsers are affected?
@angular/core 6.0.4 @angular/material 6.2.1 @angular/cdk 6.2.1 Chrome 67.0.3396.79 Firefox 60.0.2 Safari 11.1
Is there anything else we should know?
This happens with all animations I have tested, not just the one provided in the stackblitz example.