Если вы используете динамически создаваемые компоненты в Angular, вам, вероятно, сложно передавать информацию между родительским и дочерним компонентами, когда это необходимо. Вам необходимо предоставить информацию в родительском компоненте, а затем внедрить ее в дочерний компонент. Хотя это не обязательно сложно сделать, это приводит к появлению большого количества дополнительного шаблонного кода.
Было бы намного лучше, если бы мы могли просто использовать декоратор @Input
, как мы привыкли. Ну, угадайте, что? Angular поддерживает именно это, начиная с шестнадцатой версии. В этом посте я покажу вам, как это сделать. Хорошо, давайте перейдем к делу.
Во-первых, давайте посмотрим, как мы раньше передавали данные динамически создаваемым компонентам от родителя. Здесь, в этом примере, в шаблоне компонента у нас есть *ngComponentOutlet
, и мы передаем его нашему компоненту проигрывателя.
В этом случае мы также передаем пользовательский дочерний инжектор, и именно так мы раньше вводили данные для дочернего компонента.
@Component({ selector: 'app-root', template: ` <ng-container *ngComponentOutlet="playerComponent; injector: childInjector"></ng-container> ` }) export class App { protected playerComponent = PlayerComponent; }
И чтобы создать этот дочерний инжектор, нам нужно было создать свойство, чтобы его можно было установить и затем использовать в шаблоне.
export class App { protected childInjector?: Injector; ... }
Затем нам нужно было внедрить инжектор из ядра angular в конструктор.
export class App { ... constructor(private injector: Injector) { } }
После этого нам нужно было установить дочерний инжектор, используя метод create и массив провайдеров, чтобы предоставить дочернему токену наш токен игрока.
export class App { ... constructor(private injector: Injector) { this.childInjector = Injector.create({ providers: [ { provide: PlayerToken, useValue: this.player } ], parent: this.injector }); } }
И, наконец, в дочернем компоненте, нашем компоненте player, нам нужно было установить свойство player с помощью метода inject из ядра Angular.
export class PlayerComponent { protected player?: Player = inject(PlayerToken); }
Итак, все это делается для того, чтобы передать простой объект игрока динамическому компоненту. Я имею в виду, что если бы это не был динамический компонент, мы бы просто сделали его @Input
и просто привязали объект данных игрока к @Input
в родительском элементе. Но это динамически создаваемый компонент, поэтому мы не можем этого сделать, верно?
Что ж, начиная с Angular шестнадцати, мы фактически можем использовать @Input
вместо этого, и это намного проще, чем то, что мы видели до сих пор.
*ngComponentOutlet
Вместо этого мы начнем с изменения этого свойства player на @Input
. И он просто вводится в интерфейс нашего плеера.
export class PlayerComponent { @Input() player?: Player; }
Теперь мы можем удалить метод инъекции и импорт токенов игрока, поскольку они больше не нужны. Затем, вернувшись к нашему родительскому элементу, в шаблоне, мы можем удалить инжектор и вместо этого заменить его объектом ввода. Мы можем передать этот объект на любое количество входов. Итак, если бы у нас было пять входных данных, мы бы просто включили их имена, а затем передали каждому необходимые нам данные.
Но в данном случае у нашего дочернего компонента, player, есть только один ввод, так что это все, что нам нужно для его передачи.
@Component({ selector: 'app-root', template: ` <ng-container *ngComponentOutlet="playerComponent; inputs: { player }"></ng-container> ` })
Теперь мы можем снять дочерний инжектор. Это означает, что мы также можем вообще удалить конструктор. И, наконец, мы можем удалить инжектор из ядра Angular и импорт токенов игрока, поскольку мы их больше не используем.
export class App { protected player: Player = { name: 'LeBron James', games: 1421, points: 38652, fieldGoalPercentage: 0.505, threePointPercentage: 0.345, imageName: 'lebron-james' }; protected playerComponent = PlayerComponent; }
Вот и все. Мы видим, что все работает так же, как и раньше. Таким образом, это намного проще реализовать и меньше кода, что всегда здорово.
Однако есть один облом: хотя @Input
поддерживаются, @Output
— нет. Какой-то облом, но это то, что есть. Надеюсь, они добавят поддержку в будущем, потому что это тоже будет очень удобно, но нам просто придется подождать и посмотреть.
Ознакомьтесь с демонстрационным кодом и примерами этих методов в примере Stackblitz ниже. Если у вас есть какие-либо вопросы или мысли, не стесняйтесь оставлять комментарии.