过滤 Child 中的内容 Angular 2+
Filtering Child Content in Angular 2+
我有两个 Angular 组件(手风琴 > 扩展面板)需要在没有框架的情况下编写。我正在使用 ContentChild 来支持手风琴组件中包含的所有扩展面板。我想要做的是解析组件以检查它们的状态并从 parent 容器中切换更新 属性 上的值。
现在我在每个 expansion-panel 中都有一个事件发射器,它会在每个实例打开或关闭时发射。
我需要跟踪每个 ChildContent state$ 并在检查每个 ChildContent 状态后设置一个默认值(如果有的话),并跟踪任何更改(如果内部 child 实例被切换),它应该将事件发送到parent 手风琴,以便它可以确定要跟踪哪个索引展开。
我希望循环遍历 ChildContent 的每个实例并检查是否有任何已打开,如果没有通过更改其状态打开第一个实例。在包装器中,我订阅了每个面板并循环检查它们是否打开,如果 none 打开我希望扩展第一个 child.
每当 child 面板展开时,我希望收缩除了选定的那个之外剩余的 child 个手风琴。
@Component({
selector: 'app-accordion',
templateUrl: './accordion.component.html'
})
export class AccordionComponent extends Destroyable implements AfterContentInit, OnDestroy {
@ContentChildren(ExpansionPanelComponent) expansionPanels: QueryList<ExpansionPanelComponent>;
...
这是内部 child 组件(扩展面板)
@Component({
selector: 'app-expansion-panel',
templateUrl: './expansion-panel.component.html'
})
export class ExpansionPanelComponent extends Destroyable implements OnInit, OnDestroy {
@Input() title!: string;
@Input() content!: string | string[];
/**
* The default for this input would be overwritten if the optional
* @Input() defaultState is provided during initialization.
* The defaultState override occurs inside of this.setDefaultState();
*/
@Input() defaultState: ExpansionPanelState = ExpansionPanelState.Collapsed;
@Input() footerContent?: string;
@Input() headerIcon?: IconName;
@Input() toggleButton?: ViewChild;
@Output() expanded$ = new EventEmitter<ExpansionPanelState>();
setState(expansionPanelState: ExpansionPanelState): void {
if (this.expanded$.observers.length > 0) {
this.expanded$.emit(expansionPanelState);
}
this.state$.next(expansionPanelState);
}
这是容器组件 (Accordion) 模板,让您了解这应该是多么简单...
{{ accordionTitle }}
{{ accordionSubtitle }}
/** '
* ContentChildren 将所有 child 组件呈现为已展开,不
* 不管我尝试过什么方法。我已确认该活动正在进行中
* 发送到 parent,我还看到各个面板在切换时
* 预计。拿不到的是描述的动态互斥行为
* 上面当用户展开一个面板时,它应该收缩其余部分。什么时候
*面板是单独使用的,应该可以配置使用
* 独立于手风琴(现在很好)。如何 map/mutate/set
* 这一次我动态调整了 child 的值
* 组件状态?
*/
问题是,由于 ContentChild 被包装在一个中,所以我无法在使用 ContentChild.prototype.map 方法后将映射版本重新分配回它,我想避免手动渲染组件的开销。
扩展面板工作正常,单元测试,以及所有。手风琴和扩展面板的过滤和选择让我很困惑。我不断得到无限循环等,我知道我必须有一种更简单的方法来动态更新 ContentChildren,任何人都可以引导我朝着正确的方向前进吗?
那么如何从其包装器组件中查询然后更新 ContentChildren?
https://codesandbox.io/s/silly-river-jsbuu?file=/src/app/accordion/accordion.component.ts:0-2156
映射将在 AccordionComponent.ngAfterContentInit() 中进行,但我无法使用下面链接的交互式沙箱中的方法使其工作。
谢谢!
要完成你在问题中要求的一件事, 在你的手风琴中,初始化所有关闭的面板,可以通过迭代已经存在的值来完成 expansionPanels
实例属性:
import { ExpansionPanelState } from "PATH/TO/FILE/expansion-panel.model";
ngAfterContentInit() {
this.expansionPanels
.forEach(panel => panel.setState(ExpansionPanelState.Collapsed));
}
作为建议: 在您的 ExpansionPanelComponent
模板中,无需将状态发送回 typescript 代码,因为您已经可以在其中访问它。所以将其更改为:
<header (click)="toggle()"...
现在让我们对 toggle
方法进行一些修改以获取 BehaviorSubject
的当前状态,而不是解构它以获取其值。我们几乎不需要做任何事情,因为 BehaviorSubject
已经将最后一个值重新发送给新订阅者。我们将使用 take
运算符来确保我们将在最后一次发射后取消订阅:
import {take} from 'rxjs/operators';
...
toggle(): void {
this.state$.pipe(take(1)).subscribe((value: ExpansionPanelState) => {
switch (value) {...}
});
}
我有两个 Angular 组件(手风琴 > 扩展面板)需要在没有框架的情况下编写。我正在使用 ContentChild 来支持手风琴组件中包含的所有扩展面板。我想要做的是解析组件以检查它们的状态并从 parent 容器中切换更新 属性 上的值。
现在我在每个 expansion-panel 中都有一个事件发射器,它会在每个实例打开或关闭时发射。
我需要跟踪每个 ChildContent state$ 并在检查每个 ChildContent 状态后设置一个默认值(如果有的话),并跟踪任何更改(如果内部 child 实例被切换),它应该将事件发送到parent 手风琴,以便它可以确定要跟踪哪个索引展开。
我希望循环遍历 ChildContent 的每个实例并检查是否有任何已打开,如果没有通过更改其状态打开第一个实例。在包装器中,我订阅了每个面板并循环检查它们是否打开,如果 none 打开我希望扩展第一个 child.
每当 child 面板展开时,我希望收缩除了选定的那个之外剩余的 child 个手风琴。
@Component({
selector: 'app-accordion',
templateUrl: './accordion.component.html'
})
export class AccordionComponent extends Destroyable implements AfterContentInit, OnDestroy {
@ContentChildren(ExpansionPanelComponent) expansionPanels: QueryList<ExpansionPanelComponent>;
...
这是内部 child 组件(扩展面板)
@Component({
selector: 'app-expansion-panel',
templateUrl: './expansion-panel.component.html'
})
export class ExpansionPanelComponent extends Destroyable implements OnInit, OnDestroy {
@Input() title!: string;
@Input() content!: string | string[];
/**
* The default for this input would be overwritten if the optional
* @Input() defaultState is provided during initialization.
* The defaultState override occurs inside of this.setDefaultState();
*/
@Input() defaultState: ExpansionPanelState = ExpansionPanelState.Collapsed;
@Input() footerContent?: string;
@Input() headerIcon?: IconName;
@Input() toggleButton?: ViewChild;
@Output() expanded$ = new EventEmitter<ExpansionPanelState>();
setState(expansionPanelState: ExpansionPanelState): void {
if (this.expanded$.observers.length > 0) {
this.expanded$.emit(expansionPanelState);
}
this.state$.next(expansionPanelState);
}
这是容器组件 (Accordion) 模板,让您了解这应该是多么简单...
{{ accordionTitle }} {{ accordionSubtitle }} /** ' * ContentChildren 将所有 child 组件呈现为已展开,不 * 不管我尝试过什么方法。我已确认该活动正在进行中 * 发送到 parent,我还看到各个面板在切换时 * 预计。拿不到的是描述的动态互斥行为 * 上面当用户展开一个面板时,它应该收缩其余部分。什么时候 *面板是单独使用的,应该可以配置使用 * 独立于手风琴(现在很好)。如何 map/mutate/set * 这一次我动态调整了 child 的值 * 组件状态? */问题是,由于 ContentChild 被包装在一个中,所以我无法在使用 ContentChild.prototype.map 方法后将映射版本重新分配回它,我想避免手动渲染组件的开销。
扩展面板工作正常,单元测试,以及所有。手风琴和扩展面板的过滤和选择让我很困惑。我不断得到无限循环等,我知道我必须有一种更简单的方法来动态更新 ContentChildren,任何人都可以引导我朝着正确的方向前进吗?
那么如何从其包装器组件中查询然后更新 ContentChildren?
https://codesandbox.io/s/silly-river-jsbuu?file=/src/app/accordion/accordion.component.ts:0-2156
映射将在 AccordionComponent.ngAfterContentInit() 中进行,但我无法使用下面链接的交互式沙箱中的方法使其工作。
谢谢!
要完成你在问题中要求的一件事, 在你的手风琴中,初始化所有关闭的面板,可以通过迭代已经存在的值来完成 expansionPanels
实例属性:
import { ExpansionPanelState } from "PATH/TO/FILE/expansion-panel.model";
ngAfterContentInit() {
this.expansionPanels
.forEach(panel => panel.setState(ExpansionPanelState.Collapsed));
}
作为建议: 在您的 ExpansionPanelComponent
模板中,无需将状态发送回 typescript 代码,因为您已经可以在其中访问它。所以将其更改为:
<header (click)="toggle()"...
现在让我们对 toggle
方法进行一些修改以获取 BehaviorSubject
的当前状态,而不是解构它以获取其值。我们几乎不需要做任何事情,因为 BehaviorSubject
已经将最后一个值重新发送给新订阅者。我们将使用 take
运算符来确保我们将在最后一次发射后取消订阅:
import {take} from 'rxjs/operators';
...
toggle(): void {
this.state$.pipe(take(1)).subscribe((value: ExpansionPanelState) => {
switch (value) {...}
});
}