Как получить элемент после его отображения с помощью *ngIf?

Я часто сталкиваюсь с этой проблемой. У меня есть элемент, как показано

<div class="element-1" *ngIf="isShown"></div>

по умолчанию isShown = false; и, щелкнув элемент, я делаю isShown = true;

Теперь в той же функции обратного вызова клика. Если я попытаюсь получить element-1 как

$('.element-1'), я не получаю этот элемент, потому что он может отсутствовать в DOM сразу после того, как isShown = true.

Я могу получить то же самое, используя ngAfterContentChecked. Но ngAfterContentChecked звонил много раз.

Итак, как я могу получить элемент, не используя ngAfterContentChecked?

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

Это мой элемент

<app-card-kpi-inline-overlay #kpisOverlay class="child-component all-kpis-overlay-wrap {{selectedView}}" [style.left.px]="kpiLeft" *ngIf="data['openKpiDetails']==true" [cardData]="data"></app-card-kpi-inline-overlay>

Это мой код метода ts

@ViewChild('kpisOverlay') kpisOverlay: ElementRef;

showKpiSection(i, event, card) {
    card['openKpiDetails'] = !card['openKpiDetails'];
    event.stopPropagation();
    if (card['openKpiDetails']) {
        setTimeout(() => { 
            const el: HTMLElement = this.kpisOverlay.nativeElement; 
            console.log(el); // always showing undefined
        }, 0);
    }
}

Я пытаюсь переключить флаг. Но консоль всегда печатает undefined.

Ниже мой элемент переключения

<div (click)="showKpiSection(i, $event, data)">Get element</div>

person Mr_Perfect    schedule 14.02.2018    source источник
comment
Использование jquery с angular обычно не рекомендуется. Расскажите нам, что вы пытаетесь сделать после выбора элемента. Возможно, есть способ сделать это без jquery.   -  person charsi    schedule 14.02.2018
comment
Почему вы хотите получить элемент DOM? Angular построен с привязкой данных. Получить div по идентификатору или классу через JQuery не рекомендуется.   -  person Pterrat    schedule 14.02.2018
comment
Я хочу динамически применять ширину после установки флага в значение true.   -  person Mr_Perfect    schedule 14.02.2018
comment
Я обновил свой вопрос. Пожалуйста, пройдите через это   -  person Mr_Perfect    schedule 14.02.2018
comment
Отвечает ли это на ваш вопрос? Событие, которое срабатывает, когда оператор angular *ngIf оценивает в шаблоне   -  person Luis Limas    schedule 18.03.2021


Ответы (3)


Я никогда не скажу этого достаточно:

Использование JQuery с Angular — это антишаблон. Вы не должны трогать DOM самостоятельно, вы должны позволить фреймворку сделать это за вас.

Теперь в полном ANgular:

<div #firstElement *ngIf="isShown"></div>

В вашем ТС:

@ViewChild('firstElement') firstElement: ElementRef;

Если вы хотите, чтобы элемент в вашей функции, как только значение isShown установлено в true, используйте это

const el: HTMLElement = this.firstElement.nativeElement;

Если это не сработает, активируйте обнаружение изменений, потому что это означает, что Angular еще не закончил обнаружение изменений.

EDIT Поскольку ваш компонент находится в цикле, вместо него следует использовать @ViewChildren.

Я сделал рабочий StackBlitz для вас посмотрите на код, это в основном тот же принцип, только элемент становится массивом элементов.

person Community    schedule 14.02.2018
comment
Нет, я не могу получить элемент. Отображение неопределенного. Как я могу активировать обнаружение изменений? Какие шаги я должен сделать, чтобы получить элемент и динамически добавить ему ширину? - person Mr_Perfect; 14.02.2018
comment
чтобы вызвать обнаружение изменений, быстрее всего просто использовать тайм-аут с setTimeout(() => {const el: HTMLElement = this.firstElement.nativeElement;}). Как только вы получите элемент, просто выполните el.style.width = el.offsetWidth + 30 + 'px' - person ; 14.02.2018
comment
Я обновил свой код. Я все еще получаю неопределенное значение - person Mr_Perfect; 14.02.2018
comment
Поскольку ваше условие *ngIf="data['openKpiDetails']==true", но в вашем коде вы никогда не устанавливаете для него значение true. Это означает, что ваш элемент никогда не появляется, поэтому вы становитесь неопределенным. - person ; 14.02.2018
comment
card['openKpiDetails'] = !card['openKpiDetails']; этот оператор переключает переменную. Пожалуйста, перепроверьте - person Mr_Perfect; 14.02.2018
comment
data отличается от card. Если вы используете функцию или метод доступа, было бы неплохо знать об этом. В противном случае это две разные переменные. - person ; 14.02.2018
comment
Ой, извини. при нажатии я передаю data и учтите, что оба одинаковы - person Mr_Perfect; 14.02.2018
comment
Итак, что произойдет, если вы поместите задержку в одну секунду в свой тайм-аут? Работает ли тогда? - person ; 14.02.2018
comment
Нет, this.kpisOverlay печатает класс Component со своими свойствами. не как элемент DOM, а как компонент. this.kpisOverlay.nativeElement печатает undefined. - person Mr_Perfect; 14.02.2018
comment
Поскольку nativeElement — это элемент HTML, kpisOverlay — это объект Angular (ElementRef). Если даже задержка в одну секунду не работает, значит, у вас что-то не так с вашим кодом, что не позволяет отображать ваш компонент. ваш компонент на вашем экране? видишь ? - person ; 14.02.2018
comment
Да, это отображается, но я просто хочу динамически применять некоторые стили. Для этого я получаю к нему доступ. Но я не могу получить его как элемент DOM - person Mr_Perfect; 14.02.2018
comment
Тогда мне понадобится MCVE, потому что вы либо делаете что-то не так, чем не делились SOF, или у вас есть уникальная проблема, о которой необходимо сообщить команде Angular. - person ; 14.02.2018
comment
Подождите... этот элемент находится в *ngFor? @Mr_Perfect - person ; 14.02.2018
comment
Да. Это там в петле. И я попытался переместить компонент в оболочку, поскольку ссылка не работает в селекторе компонентов. Теперь он работает, но перед установкой ширины в тайм-ауте есть небольшой рывок, даже если я использую 0 секундную задержку в тайм-ауте. - person Mr_Perfect; 14.02.2018
comment
Видите, вот почему вы должны опубликовать весь свой код. Вот stackblitz, чтобы показать вам рабочий код. - person ; 14.02.2018
comment
Но нет правильного *ngIf, и почему ссылки не работают в селекторе компонентов? - person Mr_Perfect; 14.02.2018
comment
Теперь есть ;) и не могли бы вы перефразировать свой вопрос? - person ; 14.02.2018

Вы должны определить свой элемент следующим образом:

<div #element-1 class="element-1" *ngIf="isShown"></div>

А затем получить к нему доступ с помощью

@ViewChild('element-1') element1;

в вашем Компоненте. Пример на этой странице выглядит близко к тому, что вы пытаетесь сделать: https://angular.io/api/core/ViewChild

person Vincent Gagnon    schedule 14.02.2018

Вы можете воспользоваться преимуществами поведения @ViewChild и @ViewChildren:

Декоратор свойств, который настраивает запрос представления. Детектор изменений ищет первый элемент или директиву, соответствующую селектору в представлении DOM. Если представление DOM изменяется и новый дочерний элемент соответствует селектору, свойство обновляется.

<сильный>1. Подход ViewChild с использованием setter

Важной частью является Если DOM представления изменяется, что означает, что в этом случае это будет срабатывать только при создании или уничтожении элемента.

Сначала объявите имя переменной для элемента, для примера я использовал #element1

<div #element1 class="element-1" *ngIf="isShown"></div>

Затем добавьте ссылку @ViewChild внутри вашего компонента:

@ViewChild('element1') set element1(element) {
  if (element) {
     // here you get access only when element is rendered (or destroyed)
  }
}

<сильный>2. Подход ViewChildren с использованием Observables

Другое решение — подписаться на @ViewChildren change observable вместо использования @ViewChild, например:

@ViewChildren('element1')
private element1: QueryList<any>;

А затем подпишитесь на его наблюдаемое изменение:

element1.changes.subscribe((d: QueryList<any>) => {
  if (d.length) {
    // here you get access only when element is rendered
  }
});

Я предпочел последний способ, потому что мне было проще обрабатывать наблюдаемые объекты, чем проверки внутри setter's, а также этот подход ближе к концепции Event.

person Luis Limas    schedule 18.03.2021