[英]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.