如何使用 *ngIf 显示元素后获取元素?

问题描述 投票:0回答:4

我经常遇到这个问题。我有一个如图所示的元素

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

默认情况下,

isShown = false;
,通过单击一个元素,我正在制作
isShown = true;

现在,在同一个点击回调函数中,如果我尝试获取

element-1
as

$('.element-1')
,我没有获取该元素,因为当
isShown = true
时它可能不会立即出现在 DOM 中。

我可以使用

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>
angular angular-ng-if
4个回答
7
投票

我永远不会说够:

将 JQuery 与 Angular 结合使用是一种反模式。你不应该自己接触 DOM,你应该让框架为你做这件事

现在,以完整的 Angular 方式:

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

在您的 TS 中:

@ViewChild('firstElement') firstElement: ElementRef;

如果您想要该元素,在您的函数中,一旦

isShown
的值设置为 true,请使用此

const el: HTMLElement = this.firstElement.nativeElement;

如果不起作用,请触发更改检测,因为这意味着 Angular 尚未完成更改检测。

编辑 由于您的组件处于循环中,因此您应该使用

@ViewChildren
代替。

我给你做了一个可行的StackBlitz,看代码,原理基本一样,只不过元素变成了元素数组。


5
投票

您可以利用

@ViewChild
@ViewChildren
行为:

配置视图查询的属性装饰器。变化检测器 查找与选择器匹配的第一个元素或指令 视图 DOM。如果视图 DOM 发生变化,并且新的子级与 选择器,属性已更新。

作为一般建议,如果可能的话,优先选择第三种方法而不是其他方法。因为它更自然,因为 Angular 的目的是使用。


1.使用
setter

的 ViewChild 方法

重要的部分是如果视图 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.使用 Observables 的 ViewChildren 方法

另一个解决方案是订阅

@ViewChildren
改变可观察的,而不是使用
@ViewChild
这样写:

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

然后订阅它change observable:

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

我更喜欢

ViewChildren
方式,因为对我来说,处理可观察量比在
setter's
内部验证更容易,而且这种方法更接近“事件”概念。


3. ngAfterViewInit() 作为组件事件

添加在子组件的

ngAfterViewInit
方法内触发的事件(如果可能,首选此方法而不是其他方法)。

子组件

app-card-kpi-inline-overlay
:

// declare the event
@Output()
public created= new EventEmitter<any>();

// later on, trigger the event every time the component is rendered
ngAfterViewInit() {
    this.created.next(this);
}

父组件:

<app-card-kpi-inline-overlay #kpisOverlay (created)="onComponentCreated($event)"></app-card-kpi-inline-overlay>
onComponentCreated(elem: CardKpiInlineOverlayComponent) {
    // here you get access only when element is rendered
}

2
投票

你应该像这样定义你的元素:

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

然后使用

访问它
@ViewChild('element-1') element1;

在您的组件中。 此页面上的示例看起来与您想要执行的操作很接近: https://angular.io/api/core/ViewChild


0
投票

对我来说,当我从 viewChiled 装饰器中删除属性 static 时它就起作用了

@ViewChild('mainTextBox', {read: ElementRef, static: true}) public parentTextBoxElement: ElementRef<HTMLElement>;

@ViewChild('mainTextBox', {read: ElementRef}) public parentTextBoxElement: ElementRef<HTMLElement>;

© www.soinside.com 2019 - 2024. All rights reserved.