Angular:如何在访问其nativeFlements之前等待元素准备好?

时间:2017-12-20 21:42:34

标签: angular

我试图绘制两个由一条线连接的div(每个包含组件)。行的长度取决于div的宽度,我使用nativeElement属性访问它。

当我在模板中使用[style.width]属性,并使用nativeElements调用函数来计算宽度时,我收到此错误:

ERROR TypeError: Cannot read property 'nativeElement' of undefined
    at BeanViewComponent.webpackJsonp.../../../../../src/app/pages/shared/stringbean/beans/beanView.component.ts.BeanViewComponent.getWidth (beanView.component.ts:81)
    at Object.eval [as updateRenderer] (BeanViewComponent.html:14)
    at Object.debugUpdateRenderer [as updateRenderer] (core.es5.js:13094)
    at checkAndUpdateView (core.es5.js:12241)
    at callViewAction (core.es5.js:12601)
    at execEmbeddedViewsAction (core.es5.js:12559)
    at checkAndUpdateView (core.es5.js:12237)
    at callViewAction (core.es5.js:12601)
    at execComponentViewsAction (core.es5.js:12533)
    at checkAndUpdateView (core.es5.js:12242)
    at callViewAction (core.es5.js:12601)
    at execEmbeddedViewsAction (core.es5.js:12559)
    at checkAndUpdateView (core.es5.js:12237)
    at callViewAction (core.es5.js:12601)
    at execEmbeddedViewsAction (core.es5.js:12559)

这是模板:

<div class="bean-view" (click)="backgroundClick.emit()"> 
  <div class="bean-label-container" *ngIf="showLabels">
    <div class="bean-label" *ngFor="let label of bean.labels">{{label}}</div>
  </div>
  <div class="bean-icon-container" #beanIconContainerElement>
    <sb-bean-icon [type]="bean.type"></sb-bean-icon>
  </div>
  <div *ngIf="bean" class="bean" (click)="contentClick.emit()" #beanElement>
    <sb-bean-content [class.disable-click]="disableContentClick" [bean]="bean"></sb-bean-content>
  </div>
  <div class="bean-complete-marker completion-line" [style.width]="getWidth()"></div>
  <div class="bean-response-wrapper">
    <div class="bean-response" *ngFor="let response of bean.response" (click)="responseClick.emit()" #beanResponseElement>
      <sb-bean-content [bean]="response" [isResponse]="true"></sb-bean-content>
    </div>
  </div>
</div>

以下是组件代码:

import {
  Component,
  OnInit,
  ChangeDetectionStrategy,
  Input,
  Output,
  EventEmitter,
  ViewChild,
  ElementRef
} from '@angular/core';
import { Bean } from '../../../../shared/model';

@Component({
  selector: 'bean-view',
  templateUrl: './beanView.html',
  styleUrls: ['./beanView.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class BeanViewComponent implements OnInit {
  @Input() bean: Bean;
  @Input() disableContentClick: Bean;
  @Input() showLabels: boolean;

  @Output() contentClick = new EventEmitter();
  @Output() responseClick = new EventEmitter();
  @Output() backgroundClick = new EventEmitter();

  @ViewChild('beanIconContainerElement') beanIconContainerElement;
  @ViewChild('beanElement') beanElement;
  @ViewChild('beanResponseElement') beanResponseElement;

  constructor() {
  }
  ngOnInit() {
  }

  getWidth(): string {
    const bound: number = 200;
    const iconWidth: number = this.beanIconContainerElement.nativeElement.offsetWidth;
    const beanWidth: number = this.beanElement.nativeElement.offsetWidth;
    const width: number = bound - (iconWidth + beanWidth);
    return String(width) + 'px';
  }
}

3 个答案:

答案 0 :(得分:1)

尝试将代码置于

ngAfterViewInit() { }

此时html应该完全呈现。

答案 1 :(得分:1)

可能的解决方案:

public dynamicWidth: number = undefined;

ngAfterViewInit() {
   this.dynamicWidth = this.getWidth();
}

getWidth(): number {
  const bound: number = 200;
  const iconWidth: number = 
  this.beanIconContainerElement.nativeElement.offsetWidth;
  const beanWidth: number = this.beanElement.nativeElement.offsetWidth;
  const width: number = bound - (iconWidth + beanWidth);
  return width;
}

template:

<div *ngIf="dynamicWidth" [style.width.px]="dynamicWidth"></div>

或者,如果您使用的是flexbox,则可能会放弃整个宽度计算并执行类似

的操作
.bean-view {
    display: flex;
}
.completion-line {
    flex: auto;
}

可能有很多其他方法可以做到这一点,但上面首先想到的是最接近你已经做过的事情。

答案 2 :(得分:0)

好吧,这个技巧起作用了: onInit做:

this.getWidth();

和getWidth应该看起来像这样:

getWidth(): string {
if (this.beanIconContainerElement.nativeElement.offsetWidth > 0 && this.beanElement.nativeElement.offsetWidth > 0) {
    const bound: number = 200;
    const iconWidth: number = this.beanIconContainerElement.nativeElement.offsetWidth;
    const beanWidth: number = this.beanElement.nativeElement.offsetWidth;
    const width: number = bound - (iconWidth + beanWidth);
    return String(width) + 'px';
  }
} else {
setTimeout(() => {
this.getWidth();}, 500);