Как выбрать ContentChild для собственного элемента в Angular 6?

У меня есть компонент, использующий проекцию контента.

<ng-content select = "button">
</ng-content>

Я хочу сделать что-то подобное в своем компоненте:

@ContentChild('button') button: ElementRef;

Однако, когда я проверяю this.button, это undefined как в ngAfterViewInit, так и в ngAfterContentInit.

Как я могу выбрать свой дочерний контент, если это собственный элемент, а не пользовательский компонент?

Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
5
0
9 860
2

Ответы 2

Ни один из декораторов запросов не может выбирать собственные элементы без ссылки.

@ViewChild('button')
@ViewChildren('button')
@ContentChild('button')
@ContentChildren('button')

Это не селектор CSS.

Декораторы запросов ищут в графе зависимостей соответствующий тип и выбирают их. Соответствующий тип может быть ссылкой на шаблон, компонентом или директивой.

Рекомендуемый подход для выбора определенных элементов в содержимом - пометить его директивой.

@Directive({...})
export class MyButtonDirective {}

Теперь вы можете запросить это в своем родительском компоненте.

@ContentChild(MyButtonDirective) button: MyButtonDirective;

Когда вы используете строковое значение, оно относится к ссылке на переменную шаблона. Они написаны как #someValue и могут быть ссылкой на шаблон, компонентом или директивой.

<button #myButton></button>

Теперь вы можете ссылаться на приведенное выше как

@ViewChild('myButton')

Я не знаю, работает ли это для ContentChild, из-за того, как работают представления. Переменная шаблона #myButton может не отображаться в родительском графе зависимостей.

В качестве альтернативы вы можете ввести ElementRef родительского компонента, а затем использовать собственный JavaScript для поиска детей, которые вы ищете. Это плохая практика с точки зрения Angular, потому что идея состоит в том, чтобы отделить ваше приложение от DOM.

Я собирался опубликовать ответ со ссылочной переменной шаблона, и я могу подтвердить, что он работает с @ContentChild, если вы получите доступ к нему в ngAfterContentInit. См. этот stackblitz.

ConnorsFan 03.08.2018 15:54

@ConnorsFan круто. Я обычно так не делаю. Если я видел #myButton в шаблоне и не видел, чтобы он использовался где-либо в этом шаблоне, я мог бы удалить его. Так что вы должны назвать их как-то вроде #myButtonForParent.

Reactgular 03.08.2018 15:56

@ConnorsFan круто, это действительно работает, но это означает, что AppComponent должен знать, что он должен использовать кнопку с определенным шаблоном ref myButton. Это то, о чем ему не следует знать. Вы так не думаете?

Yulian 03.08.2018 15:59

@Yulian Я создал общие директивы кнопок, в которых в качестве селектора используется только button. Затем вы можете запросить те, а другие компоненты не знают, что это происходит. Вы просто должны быть осторожны, никто другой не использует тот же селектор.

Reactgular 03.08.2018 16:21

Важно понимать, что селектор, который вы передаете @ContentChild, является нет селектором CSS, и вы не можете найти дочерний контент на основе его идентификатора, класса или типа элемента. Вы можете искать только по имени идентификатора, которое вы ему дали, используя оператор #.

Итак, учитывая компонент под названием my-comp и следующее использование:

<my-comp><button #buttonName>Click me</button></my_comp>

Вы можете найти его, используя:

@ContentChild('buttonName') button: ElementRef;

Редактировать

Как отмечено в комментарии OP к ответу ckTag (он опередил меня на минуту), это означает, что вызывающий код должен знать, что вы ожидаете, что контент будет помечен определенным именем.

Если ваш компонент действительно использует нужно, чтобы знать подробности своего дочернего содержимого, лучшим ответом будет предоставление типа директивы для @ContentChild:

@ContentChild(MyButtonComponent, { read: ElementRef })
button: ElementRef;

Это также лучше, потому что теперь вы можете реально ожидать, что будете знать тип контента; в конце концов, код вызова может вставить #button в div, если ему так хочется.

Это означает попрощаться с использованием обычного элемента HTML button, но имеет и другие преимущества. Вы можете, например, предоставить сообщение, которое будет направлять ваш код вызова, например:

<ng-content></ng-content>
<div *ngIf = "button">Error: Please provide a MyButtonComponent</div>

@CobusKruger на самом деле, вызывающий код не должен разрешать ничего, кроме собственных элементов кнопки, если у вас есть <ng-content select = "button"> </ng-content>, не так ли?

Yulian 03.08.2018 16:24

@Yulian Я пропустил, что вы использовали select. Я все еще обычно использую это со своими собственными директивами, а это означает, что вызывающему коду не нужно знать такие вещи, как «использовать это ссылочное имя шаблона для кнопки». Таким образом, требование ссылочной переменной шаблона с заданным именем технически может быть тем ответом, который вы просили, но, как вы предположили, это неинтуитивно.

Cobus Kruger 03.08.2018 16:40

Другие вопросы по теме