简体   繁体   English

在Angular2中使用@Input装饰器初始化属性的正确方法是什么?

[英]What is the proper way to initialize a property with @Input decorator in Angular2?

I've created a component in angular to handle my material autocomplete for selection an Action.我在 angular 中创建了一个组件来处理我的材料自动完成以选择一个动作。 I pass it the Action[] from the parent component.我将父组件的 Action[] 传递给它。 The autocomplete works appropriately but my display name function does not work.自动完成功能正常,但我的显示名称 function 不起作用。 I get "TypeError: Cannot read property 'filter' of undefined" after a little digging I've discovered this is because inside my displayName function this.actions is an empty array.经过一番挖掘后,我得到“TypeError:无法读取未定义的属性'过滤器'”,这是因为在我的 displayName function 中,this.actions 是一个空数组。 I feel like this.actions inside the displayName function is getting stuck with the initial value and not updating when the component loads the inputted value.我觉得 displayName function 中的 this.actions 卡在初始值上,并且在组件加载输入值时没有更新。 I know my actions property is not empty because it works as expected with the autocomplete component.我知道我的操作属性不为空,因为它与自动完成组件一起按预期工作。 Is there a proper way to initialize my actions property so that it works with my displayName()?是否有适当的方法来初始化我的操作属性,以便它与我的 displayName() 一起使用?

import {Component, Input} from '@angular/core';
import {ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR} from '@angular/forms';
import {Action} from '../../../../Interfaces/action';
import {Observable} from 'rxjs';
import {map, startWith} from 'rxjs/operators';

@Component({
  selector: 'app-input-action-typeahead',
  templateUrl: './input-action-typeahead.component.html',
  styleUrls: ['./input-action-typeahead.component.scss'],
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: InputActionTypeaheadComponent,
    multi: true
  }]
})
export class InputActionTypeaheadComponent implements ControlValueAccessor {

  @Input() actions: Action[] = [];
  filteredActions: Observable<Action[]>;
  actionCtrl = new FormControl();

  constructor() {
    this.filteredActions = this.actionCtrl.valueChanges.pipe(
      startWith(''),
      map(value => typeof value === 'string' ? value : value.name),
      map(action => action ? this._filter(action) : this.actions.slice())
    );
  }

  private _filter(value: string): Action[] {
    const filterValue = value.toLowerCase();
    return this.actions.filter(action => action.name.toLowerCase().indexOf(filterValue) !== -1);
  }

  registerOnChange(fn: any): void {
    this.actionCtrl.valueChanges.subscribe(fn);
  }

  registerOnTouched(fn: any): void {
  }

  writeValue(obj: Action): void {
  }

  displayName(id: number): string {
    if (!id) {
      return '';
    }
    return this.actions.filter(action => action.id === id)[0].name;
  }

  clear(): void {
    this.actionCtrl.setValue('');
  }

}

I suspect that you may be trying to access the actions variable value before it is set.我怀疑您可能正在尝试在设置之前访问actions变量值。 There are a couple of ways you can handle this,有几种方法可以解决这个问题,

Approach 1方法一

Check if actions has a value before trying to read it.在尝试读取操作之前检查actions是否具有值。

 displayName(id: number): string {
    if(!!id && !!this.actions){
        return this.actions.filter(action => action.id === id)[0].name;
    }

    return '';
  }

Approach 2方法二

Every time change detection is run, your function displayName will be called.每次运行更改检测时,都会调用您的 function displayName It adds a very minor performance overhead.它增加了非常小的性能开销。 To avoid that you can compute the displayName on the setter of the actions so it is not a function that gets called every time you move the mouse.为避免这种情况,您可以在操作的设置器上计算 displayName,因此它不是每次移动鼠标时都会调用的 function。 This is more code, but more efficient.这是更多的代码,但更有效。

_actions: [];
get actions(): []{
    return this._actions;
}
set actions(value: []) {
     this._actions= value;
     this.updateDisplayName();
}

updateDisplayName(actions: []): void{
        // use your actions variable here to compute the display name.
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM