#angular #angular-template #angular-ngfor
#угловой #угловой-шаблон #angular-ngfor
Вопрос:
Предположим, у меня есть «ParentComponent», который содержит список элементов (скажем, взятых в качестве входных данных) и должен отображать элементы в списке. Однако мне нужно, чтобы этот родительский компонент можно было использовать повторно, и одной из настроек, которые он будет поддерживать, будет выбор шаблона (или компонента), который он использует для отображения элементов списка. Компонент, используемый для элементов дочернего списка, может быть любым, если он может отображать элемент списка, предоставленный ему в качестве входных данных (шаблон может правильно ссылаться на свойства элемента). Это возможно в таких фреймворках, как React, поэтому мой вопрос заключается в том, возможно ли это и в Angular и как это можно сделать?
Я полагаю, что родительский компонент принимает пользовательский компонент в качестве входных данных вместе с элементами
@Input()
items: Array<ItemType>;
@Input()
componentForRenderingStuff: ?;
И шаблон, являющийся чем-то вроде этого
<div class="wrapper">
<!-- ...stuff -->
<div class="list-item" *ngFor="let i of items">
<component-for-rendering-stuff [item]="i"></component-for-rendering-stuff>
</div>
</div>
Это означало бы, что использование родительского компонента в другом шаблоне будет похоже
<app-parent-component [items]="items" [componentForRenderingStuff]="SomeComponent"></app-parent-component>
Возможно ли что-то подобное? Я посмотрел ng-content
, но не смог заставить его работать *ngFor
.
Комментарии:
1. Я думаю, что это слишком сложный подход. Это могло бы быть проще. Этот объект компонента передается дочернему элементу, это анти-шаблон. Определите компонент, который вы импортируете в свой модуль. И этот компонент можно повторно использовать где угодно. Если вы передаете данные родительскому элементу, существует аннотация @Output. Вы думали об этом?
2. Если бы я столкнулся с этой проблемой, я бы использовал ng-switch для загрузки правильного компонента и просто имел один дочерний компонент, который содержал бы другие компоненты для переключения
3. @OwenKelvin да, я уже сделал это один раз в своем приложении, и я немного беспокоюсь о том, что эти привязки постоянно активны, ожидая изменений во входных данных. Кроме того, идея заключается в том, что этот список может быть использован один раз, скажем, в раскрывающемся списке панели поиска, в другое время в каком-то совершенно другом месте и т.д. цель состоит в том, чтобы создать легкую зависимость для различных угловых модулей в приложении.
4. @Numichi Я в недоумении, не уверен, что понимаю часть «@Output» в этом контексте, поскольку это антипаттерн, он широко используется в React и с большим успехом.
5. на ум приходят два варианта, один из которых — использование решения на основе шаблонов, упомянутого @OwenKelvin. другой — динамическая загрузка компонента. у обоих есть свои плюсы и минусы. однако, если вас действительно беспокоит производительность, и вы хотите избежать обнаружения изменений, которые может вызвать наличие такого большого количества if в вашем шаблоне, тогда вам остается динамическая загрузка компонента.
Ответ №1:
Как предположил Эдвард в своем комментарии, поведение может быть достигнуто с помощью динамической загрузки компонентов.
Я нашел несколько сторонних библиотек в npm, которые решили эту проблему, и из-за времени и простоты я использовал ту, которая имела наиболее привлекательную статистику пользователей: https://www.npmjs.com/package/ng-dynamic-component
Короче говоря, общий компонент списка будет выглядеть следующим образом
@Component({
selector: 'app-list',
template: `
<div *ngFor="let item of items">
<ndc-dynamic
[ndcDynamicComponent]="listItemComponent"
[ndcDynamicInputs]="{ input: item.data }"
></ndc-dynamic>
</div>
`,
styleUrls: ['...'],
})
export class ClickableVerticalListComponent {
@Input()
listItemComponent: any;
@Input()
items: Array<any>;
constructor() {}
}
Если мы хотим использовать список с определенным пользовательским компонентом для элемента списка, мы бы сделали это следующим образом:
@Component({
selector: '...',
template: `
<app-list
[items]="items"
[listItemComponent]="ExampleComponent"
></app-list>
`,
styleUrls: ['...'],
})
export class ParentComponent {
ExampleComponent = ExampleComponent;
items: [{ data: ... }, { data: ... }];
constructor() {}
}
Комментарии:
1. рад слышать, что вы нашли решение. к вашему сведению, для дальнейшего использования в angular native есть документация по динамической загрузке компонентов здесь . удачи.