将组件拆分成更小的组件,同时保持 Angular 中父组件的 `ngModel` 和 `ngModelChange` 绑定

Posted

技术标签:

【中文标题】将组件拆分成更小的组件,同时保持 Angular 中父组件的 `ngModel` 和 `ngModelChange` 绑定【英文标题】:Split components into smaller components while keeping the `ngModel` and `ngModelChange` binding of the parent components in Angular 【发布时间】:2021-11-18 03:41:28 【问题描述】:

我有一个 main.component 需要拆分成更小的组件,同时保留父组件的 ngModelngModelChange。我怎样才能达到这样的效果?我已经尝试过this,但它似乎对 ngModelChange 没有任何作用。

例子:

//main.component.ts
@Component(
    selector: 'main-component',
    templateUrl: './main.component.html',
    styleUrls: ['./main.component.scss'],
)
export class CardRendererComponent 
    private data;
    private method() 
        //...
    

<!-- main.component.html -->
<div class="componentA" [(ngModel)]="data" (ngModelChange)="method()"></div>
<div class="componentB" [(ngModel)]="data" (ngModelChange)="method()"></div>

我应该怎么做才能保留该子组件(componentA.component.htmlcomponentB.component.html)上的 [(ngmodel)](ngModelChange) 属性,以便实现以下目标:

<!-- main.component.html -->
<componentA [(ngModel)]="data" (ngModelChange)="method()"></componentA>
<componentB [(ngModel)]="data" (ngModelChange)="method()"></componentB>

【问题讨论】:

您的较小组件需要将更改事件向上传播(@Output + EventEmitter)。 @GunnarB.:我试图想出一种更简洁的方法来做到这一点。我终于发现了使用 ControlValueAccessor 的正确方法。感谢您的意见! 【参考方案1】:

我终于找到了一种方法来正确执行此操作,而无需发出和捕获组件之间的所有事件。我将使用ControlValueAccessor。代码留在这里给以后需要的人:

//componentA.component.ts - Child component
import  Component, forwardRef  from '@angular/core';
import  ControlValueAccessor, NG_VALUE_ACCESSOR  from '@angular/forms';

@Component(
    selector: 'componentA',
    template: `<input
            [(ngModel)]="dataPassedByParent"
            (ngModelChange)="propagateChange(dataPassedByParent)"
        >`,
    providers: [
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => HeadingEditorComponent),
        multi: true 
    ],
)

export class ComponentAComponent implements ControlValueAccessor 
    dataPassedByParent;

    propagateChange = (_: any) => ;

    //Triggered when a value is written
    writeValue(data: any) 
        if (data) this.dataPassedByParent = data;
    

    //Trigger on ngModelChange
    registerOnChange(fn) 
        this.propagateChange = fn;
    

    //Trigger on touched, required but not used
    registerOnTouched = () => ;

    constructor() 

并且在父组件中:

//main.component.ts - Parentcomponent
import  Component  from '@angular/core';

@Component(
    selector: 'componentA',
    template: `
        <componentA [(ngModel)]="data" (ngModelChange)="method()"></componentA>
`,
)

export class MainComponent 
    data;

    constructor() 

    method() 
        //...
    

【讨论】:

以上是关于将组件拆分成更小的组件,同时保持 Angular 中父组件的 `ngModel` 和 `ngModelChange` 绑定的主要内容,如果未能解决你的问题,请参考以下文章

如何防止 Node.js 将套接字消息拆分成更小的块

将类名添加到 React 根组件或更改结构

React:Refs and DOM

Angular 8 - 更小的包

如何将 vue 单个组件模板部分拆分为更小的子模板

如何从另一个组件调用一个函数,同时保持另一个组件在 Angular 中的通用性?