admin管理员组文章数量:1026989
I made an accordion component (angular18) with lazy loading of it's body content and smooth animation of opening and closing. So it works pretty well when i toggle it from inside (by clicking on header), but when i toggle it from outside - it doesn't open smoothly (but closes smoothly).
Here's the stackblitz:
What's the point of this behavior? i'm quite new to Angular animations..
tried to replace model with input - same thing. Css animations with maxheight are not good enough because of different content sizes.
upd. added squares to ensure than animations works there - they do.
I made an accordion component (angular18) with lazy loading of it's body content and smooth animation of opening and closing. So it works pretty well when i toggle it from inside (by clicking on header), but when i toggle it from outside - it doesn't open smoothly (but closes smoothly).
Here's the stackblitz: https://stackblitz/edit/stackblitz-starters-rjsmkv
What's the point of this behavior? i'm quite new to Angular animations..
tried to replace model with input - same thing. Css animations with maxheight are not good enough because of different content sizes.
upd. added squares to ensure than animations works there - they do.
Share Improve this question edited Nov 16, 2024 at 17:45 argentum4k asked Nov 16, 2024 at 14:35 argentum4kargentum4k 331 silver badge5 bronze badges1 Answer
Reset to default 1I think the problem is due to mixing of signal
and observable
updates. Where the signal is updated first followed by the observable being updated later.
The scenario is there is no content inside the accordion and the signal is updated, then the animation has already started. At a later point of time the observable delayedIsOpen
is updated by that time the animation is midway or even over. This causes the jerk.
I have noticed that using both the sources as observables, solves the issue.
So we can create another observable isOpenDelayed = toObservable(this.isOpen);
just to fix the timing issue, then use this to trigger the animation.
<div
class="main-content"
[@content]="
(isOpenDelayed | async)
? { value: 'visible', params: { transitionParams } }
: { value: 'hidden', params: { transitionParams } }
"
>
@if (delayedIsOpen | async) {
<ng-container *ngTemplateOutlet="accordionBodyRef" />
}
</div>
Full Code:
HTML:
<div
class="test"
[@sqare]="
isOpen()
? { value: 'red', params: { transitionParams } }
: { value: 'blue', params: { transitionParams } }
"
>
isOpen
</div>
<p></p>
<div
class="test"
[@sqare]="
(delayedIsOpen | async)
? { value: 'red', params: { transitionParams } }
: { value: 'blue', params: { transitionParams } }
"
>
delayedIsOpen
</div>
<p></p>
<div
class="accordion"
[ngStyle]="{ '--transiton-time': transitionTime + 'ms' }"
>
<div class="accordion-head">
<div class="top-side top-side_left" (click)="toggle()">
<ng-content select="[topLeft]" />
</div>
</div>
<div
class="main-content"
[@content]="
(isOpenDelayed | async)
? { value: 'visible', params: { transitionParams } }
: { value: 'hidden', params: { transitionParams } }
"
>
@if (delayedIsOpen | async) {
<ng-container *ngTemplateOutlet="accordionBodyRef" />
}
</div>
</div>
TS:
import {
animate,
state,
style,
transition,
trigger,
} from '@angular/animations';
import {
ChangeDetectionStrategy,
Component,
input,
model,
ContentChild,
TemplateRef,
} from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { delay, of, switchMap } from 'rxjs';
@Component({
selector: 'accordion',
templateUrl: './accordionponent.html',
styleUrl: './accordionponent.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
animations: [
trigger('content', [
state(
'hidden',
style({
height: '0',
visibility: 'hidden',
})
),
state(
'visible',
style({
height: '*',
visibility: 'visible',
})
),
transition('visible <=> hidden', [animate('{{transitionParams}}')]),
transition('void => *', animate(0)),
]),
trigger('sqare', [
state(
'red',
style({
background: 'red',
})
),
state(
'blue',
style({
background: 'blue',
})
),
transition('red <=> blue', [animate('{{transitionParams}}')]),
transition('void => *', animate(0)),
]),
],
})
export class AccordionComponent {
isOpen = model<boolean>(false);
transitionTime = 500;
transitionParams = `${this.transitionTime}ms linear`;
delayedIsOpen = toObservable(this.isOpen).pipe(
switchMap((open) =>
open ? of(open) : of(open).pipe(delay(this.transitionTime))
)
);
isOpenDelayed = toObservable(this.isOpen);
@ContentChild('accordionBody', { read: TemplateRef })
accordionBodyRef: TemplateRef<unknown> | null = null;
toggle(): void {
this.isOpen.update((value) => !value);
}
}
Stackblitz Demo
I made an accordion component (angular18) with lazy loading of it's body content and smooth animation of opening and closing. So it works pretty well when i toggle it from inside (by clicking on header), but when i toggle it from outside - it doesn't open smoothly (but closes smoothly).
Here's the stackblitz:
What's the point of this behavior? i'm quite new to Angular animations..
tried to replace model with input - same thing. Css animations with maxheight are not good enough because of different content sizes.
upd. added squares to ensure than animations works there - they do.
I made an accordion component (angular18) with lazy loading of it's body content and smooth animation of opening and closing. So it works pretty well when i toggle it from inside (by clicking on header), but when i toggle it from outside - it doesn't open smoothly (but closes smoothly).
Here's the stackblitz: https://stackblitz/edit/stackblitz-starters-rjsmkv
What's the point of this behavior? i'm quite new to Angular animations..
tried to replace model with input - same thing. Css animations with maxheight are not good enough because of different content sizes.
upd. added squares to ensure than animations works there - they do.
Share Improve this question edited Nov 16, 2024 at 17:45 argentum4k asked Nov 16, 2024 at 14:35 argentum4kargentum4k 331 silver badge5 bronze badges1 Answer
Reset to default 1I think the problem is due to mixing of signal
and observable
updates. Where the signal is updated first followed by the observable being updated later.
The scenario is there is no content inside the accordion and the signal is updated, then the animation has already started. At a later point of time the observable delayedIsOpen
is updated by that time the animation is midway or even over. This causes the jerk.
I have noticed that using both the sources as observables, solves the issue.
So we can create another observable isOpenDelayed = toObservable(this.isOpen);
just to fix the timing issue, then use this to trigger the animation.
<div
class="main-content"
[@content]="
(isOpenDelayed | async)
? { value: 'visible', params: { transitionParams } }
: { value: 'hidden', params: { transitionParams } }
"
>
@if (delayedIsOpen | async) {
<ng-container *ngTemplateOutlet="accordionBodyRef" />
}
</div>
Full Code:
HTML:
<div
class="test"
[@sqare]="
isOpen()
? { value: 'red', params: { transitionParams } }
: { value: 'blue', params: { transitionParams } }
"
>
isOpen
</div>
<p></p>
<div
class="test"
[@sqare]="
(delayedIsOpen | async)
? { value: 'red', params: { transitionParams } }
: { value: 'blue', params: { transitionParams } }
"
>
delayedIsOpen
</div>
<p></p>
<div
class="accordion"
[ngStyle]="{ '--transiton-time': transitionTime + 'ms' }"
>
<div class="accordion-head">
<div class="top-side top-side_left" (click)="toggle()">
<ng-content select="[topLeft]" />
</div>
</div>
<div
class="main-content"
[@content]="
(isOpenDelayed | async)
? { value: 'visible', params: { transitionParams } }
: { value: 'hidden', params: { transitionParams } }
"
>
@if (delayedIsOpen | async) {
<ng-container *ngTemplateOutlet="accordionBodyRef" />
}
</div>
</div>
TS:
import {
animate,
state,
style,
transition,
trigger,
} from '@angular/animations';
import {
ChangeDetectionStrategy,
Component,
input,
model,
ContentChild,
TemplateRef,
} from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { delay, of, switchMap } from 'rxjs';
@Component({
selector: 'accordion',
templateUrl: './accordionponent.html',
styleUrl: './accordionponent.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
animations: [
trigger('content', [
state(
'hidden',
style({
height: '0',
visibility: 'hidden',
})
),
state(
'visible',
style({
height: '*',
visibility: 'visible',
})
),
transition('visible <=> hidden', [animate('{{transitionParams}}')]),
transition('void => *', animate(0)),
]),
trigger('sqare', [
state(
'red',
style({
background: 'red',
})
),
state(
'blue',
style({
background: 'blue',
})
),
transition('red <=> blue', [animate('{{transitionParams}}')]),
transition('void => *', animate(0)),
]),
],
})
export class AccordionComponent {
isOpen = model<boolean>(false);
transitionTime = 500;
transitionParams = `${this.transitionTime}ms linear`;
delayedIsOpen = toObservable(this.isOpen).pipe(
switchMap((open) =>
open ? of(open) : of(open).pipe(delay(this.transitionTime))
)
);
isOpenDelayed = toObservable(this.isOpen);
@ContentChild('accordionBody', { read: TemplateRef })
accordionBodyRef: TemplateRef<unknown> | null = null;
toggle(): void {
this.isOpen.update((value) => !value);
}
}
Stackblitz Demo
本文标签:
版权声明:本文标题:signals - Difference between changing input of Angular component inside and outside a component (+animations) - Stack Overflow 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://it.en369.cn/questions/1745656551a2161629.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论