首页 文章

如何在组件输入是嵌套对象数组时检测更改?

提问于
浏览
2

我正在开发一个Angular应用程序,我会使用 ngOnChanges 在组件的输入发生变化时收到通知 . 在我的情况下,它没有被触发,因为我有一个嵌套对象数组作为组件的输入 .

我有一个组件,其中我使用两个子组件,使用两个 FormControl 相同的父 FormGroup . 我将第一个formControl的 value 传递给第二个子组件,但由于在数组修改时没有发生更改检测,因此无法在第二个子组件的Input中获取新值 .

这是我的代码:

@Component({
    encapsulation: ViewEncapsulation.None,
    moduleId: module.id,
    selector: 'my-component',
    templateUrl: 'my-component.html',
    styleUrls: ['my-component.scss']
})
export class MyComponent {
    myForm: FormGroup;

    constructor(private fb: FormBuilder) {
        this.myForm = fb.group({
            documents: null,
            summary: null
        });
    }
}

这是模板文件:

<div class="content">
    <form class="ui form" [formGroup]="myForm">
        <my-component-child-one [form]="myForm.get('documents')"></my-component-one>

        <my-component-child-two [form]="myForm.get('summary')" [content]="myForm.get('documents').value"></my-component-two>
    </form>
</div>

在第一个子组件的表单控件中进行的任何更改都不会触发第二个子组件的 ngOnChanges ,因为它绑定了数组引用而不是数组内容 . 因此,对数组的任何对象所做的任何更改或对数组本身所做的任何更改都不会更改数组引用,然后不会调用 ngOnChanges() .

可能的解决方案可能是使用 ngDoCheck . 但它可能会有一个可怕的成本,因为它的频率很高 . 它变得很重,即使因为我应该使用 IterableDiffersKeyValueDiffers .

另一个解决方案可能是订阅第一个formControl的 valueChanges ,但我无法弄清楚为什么它似乎不能正常工作,有时它会遗漏一些变化......

在我的案例中,什么是最好的解决方案?

3 回答

  • 0

    您可以将整个 form:FormGroup 传递给子组件,然后无需考虑如何检测每个子组件中的更改 .

    StackBlitz EXAMPLE

    我正在开发一个Angular应用程序,当组件的输入发生变化时,我会使用ngOnChanges来获得通知 . 在我的情况下,它没有被触发,因为我有一个嵌套对象数组作为组件的输入 .

    此外,如果您确实需要检测数组值更改,则可以使用 ngDoCheck .

    NgDoCheck() 检测并执行Angular可以自行检测的更改

  • 0

    您可以从 sub-component 收听表单更改,一旦有更改,请手动运行更改检测 .

    这实际上非常有效并且表现良好 .

    从'@ angular / core'导入

    export class MySubComponent {
        @Input() form : FormGroup;
        constructor(private _cd:ChangeDetectorRef){}
        ngOnInit() {
            this.form.valueChanges.debounceTime(100).subscribe(()=>{
          //this._cd.markForCheck() only of your component is OnPush
                 this._cd.detectChanges()
              })
    
        }
    }
    

    注意 debounceTime 只是另一个很好的性能提升,使用它会让我们减少更改检测调用的次数

  • 0

    我解决了在第一个子组件上添加 Output 的问题 . 当数组更改时,它使用 EventEmitter 向父组件发出事件 . 然后父组件更改数组引用,以便第二个子组件检测到更改并触发其 ngOnChanges .

    这是代码:

    @Component({
        encapsulation: ViewEncapsulation.None,
        moduleId: module.id,
        selector: 'my-component',
        templateUrl: 'my-component.html',
        styleUrls: ['my-component.scss']
    })
    export class MyComponent {
        myForm: FormGroup;
        documents: Array<Document>;
    
        constructor(private fb: FormBuilder) {
            this.myForm = fb.group({
                documents: null,
                summary: null
            });
        }
    
        documentsChanged = () => {
            this.documents = [].concat(this.myForm.get('documents').value);
        };
    }
    

    模板:

    <div class="content">
        <form class="ui form" [formGroup]="myForm">
            <my-component-child-one [form]="myForm.get('documents')" (docs-changed)="documentsChanged()"></my-component-one>
    
            <my-component-child-two [form]="myForm.get('summary')" [content]="documents"></my-component-two>
        </form>
    </div>
    

    另一种解决方案可能是使用 localStorage 而不是 OutputEventEmitter :第一个子组件将数据(如果已更改)设置为本地存储;第二个子组件从中获取数据 .

相关问题