在 Angular 2+ 中过滤子内容



我有两个 Angular 组件(手风琴>扩展面板(,我需要在没有框架的情况下编写。我正在使用 ContentChild 来支持手风琴组件中包含的所有扩展面板。我想做的是解析组件以检查其状态并从父容器中切换更新属性的值。

现在,我在每个扩展面板中都有一个事件发射器,如果每个实例打开或关闭,它就会发出。

我需要跟踪每个 ChildContent 状态 $,并在检查每个状态后设置默认值(如果有(,如果切换了内部子实例,则跟踪任何更改,它应该将事件发出到父手风琴,以便它可以确定要跟踪的索引作为扩展。

我希望遍历 ChildContent 的每个实例,并检查是否已打开任何实例,如果没有通过更改其状态来打开第一个实例。在包装器中,我订阅每个面板并检查一个循环,如果它们是否打开,如果没有打开,我希望扩展第一个孩子。

每当子面板扩展时, 我希望收缩剩余的子手风琴, 除了选定的手风琴

.
@Component({
selector: 'app-accordion',
templateUrl: './accordion.component.html'
})
export class AccordionComponent extends Destroyable implements AfterContentInit, OnDestroy {
@ContentChildren(ExpansionPanelComponent) expansionPanels: QueryList<ExpansionPanelComponent>;
...

这是内部子组件(扩展面板(

@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);
}

这是容器组件(手风琴(模板,可以了解这应该有多简单...

{{ 手风琴标题 }} {{ 手风琴字幕 }}/** ' * ContentChildren 将所有子组件呈现为展开,否 *无论我尝试过什么方法。我已经验证了该事件正在 * 发送给家长,我还看到各个面板在切换,因为我 *期望。无法获得的是所描述的动态互斥行为 * 上面当用户展开一个面板时,它应该收缩其余的面板。什么时候 *面板单独使用,它们应该能够配置和使用 *独立于手风琴(现在很好(。如何映射/变异/设置 * 这一次我动态调整了孩子的值 * 组件状态? */问题在于,由于 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模板中,没有必要将状态发送回打字稿代码,因为你已经可以访问它。因此,请将其更改为:

<header (click)="toggle()"...

现在让我们在toggle方法中进行一些修改以获取BehaviorSubject的当前状态,而不是解构它以获取其值。我们几乎不需要做任何事情,因为BehaviorSubject已经将最后一个值重新发送到新订阅者。我们将使用take运算符来确保在获取最后一次排放后取消订阅:

import {take} from 'rxjs/operators';
...
toggle(): void {
this.state$.pipe(take(1)).subscribe((value: ExpansionPanelState) => {
switch (value) {...}
});
}

相关内容

  • 没有找到相关文章

最新更新