【问题标题】:How to get element after displaying it using *ngIf?使用 *ngIf 显示元素后如何获取元素?
【发布时间】:2018-07-25 01:28:01
【问题描述】:

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

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

默认情况下,isShown = false;,通过点击一个元素,我正在制作isShown = true;

现在,在同一个点击回调函数中如果我尝试将element-1 设为

$('.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 的 jquery。告诉我们您在选择元素后要做什么。也许有一种非 jquery 方法可以做到这一点。
  • 为什么要获取 DOM 元素? Angular 是使用数据绑定构建的。不推荐通过 JQuery 按 Id 或类获取 div
  • 我想在设置标志为true后动态应用宽度。
  • 我更新了我的问题。请通过它

标签: angular angular-ng-if


【解决方案1】:

我永远都说不够:

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

现在,以完整的角度方式:

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

在你的 TS 中:

@ViewChild('firstElement') firstElement: ElementRef;

如果你想要元素,在你的函数中,一旦isShown 的值设置为true,就使用这个

const el: HTMLElement = this.firstElement.nativeElement;

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

EDIT 由于您的组件处于循环中,因此您应该改用@ViewChildren

我为你做了一个工作StackBlitz,看代码,原理基本一样,只是元素变成了元素数组。

【讨论】:

  • 不,我无法获取元素。显示未定义。如何触发变更检测?我应该采取哪些步骤来获取元素并动态为其添加宽度?
  • 要触发变更检测,最快的方法就是使用setTimeout(() =&gt; {const el: HTMLElement = this.firstElement.nativeElement;}) 超时。获得元素后,只需执行el.style.width = el.offsetWidth + 30 + 'px'
  • 我更新了我的代码。我仍然得到未定义的价值
  • 因为您的条件是 *ngIf="data['openKpiDetails']==true" 但在您的代码中,您从未将其设置为 true。这意味着您的元素永远不会出现,这就是您变得未定义的原因。
  • card['openKpiDetails'] = !card['openKpiDetails']; 此语句切换变量。请重新检查
【解决方案2】:

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

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

然后用

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

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

【讨论】:

    【解决方案3】:

    您可以利用@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。使用 Observables 的 ViewChildren 方法

    另一种解决方案是订阅 @ViewChildren 改变 observable,而不是使用 @ViewChild 这样说:

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

    然后订阅它改变 observable:

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

    我更喜欢最后一种方式,因为对我来说,处理 observables 比处理 setter's 内部的验证更容易,而且这种方式更接近“事件”概念。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-07
      • 1970-01-01
      • 2014-12-16
      • 2020-12-18
      相关资源
      最近更新 更多