使用@Input FormGroups进行OnPush更改检测

时间:2017-08-17 12:57:23

标签: angular angular2-forms angular2-changedetection ngrx-store

想象一下Angular 2应用程序中的以下组件层次结构。

app.component
└── node.component
    ├── header.component
    ├── body.component
    └── footer.component

该应用将呈现节点树。有一个根源' ngrx/store中保存的节点,以反映树的状态。

app.component获得"切片"在AppState中保留的ngrx/store,即根节点上的Observable

export class AppComponent {
    rootNode: Observable<Node>;

    constructor(private readonly store: Store<AppState>) {
        this.rootNode = this.store.select(state => state.nodes);
    }
}

app.component使用rootNode管道和async呈现node.component(请参阅上面的组件层次结构):

<app-node [node]="rootNode | async"></app-node>

node.component收到Node Input()并使用以下三个组件呈现它:header.componentbody.componentfooter.component

@Component({
    selector: 'app-node',
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NodeComponent {
    @Input() node: Node;
    constructor() {}
}

注意,node.component视图 NOT 使用async管道,因为它不呈现Observable,而是正常的Node对象:< / p>

<node-header [node]="node"></node-header>
<node-body [node]="node"></node-body>
<node-footer [node]="node"></node-footer>

虽然这些子组件只呈现节点数据的子集,但它们接收整个节点@Input(),,以便决定如何呈现它。

重要细节:所有三个组件都会创建一个FormGroup,允许对节点进行编辑。但是,它们也呈现了可以编辑的相同值的视图,即

<input formControlName="title">
<p>Title {{ node.title }}</p>

由于header.componentbody.componentfooter.component都做了几乎相同的事情,我只提供header.component的大纲:

@Component({
    selector: 'node-header',
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HeaderComponent implements OnInit {
    @Input() node: Node;
    @Input() headerForm: FormGroup;

    constructor(private fb: FormBuilder) {}

    ngOnInit() {
        this.headerForm = this.fb.group({
            title: [this.node.title]
        });
    }
}

FormBuilder创建FormGroup并绑定到从title收到的节点的@Input() 属性<node-header>将呈现用于编辑的表单控件和值:

<div [formGroup]="headerForm">
    <input formControlName="title"name="title">
</div>
<p>Title {{ node.title }}</p>

node.componentheader.component都使用OnPush更改检测策略,因为节点数量可能会变得非常大。

问题/问题 编辑{{ node.title }}控件时,input未更新。我怀疑这是因为ngrx/store中的值没有改变,因此app.component中的Observable没有得到通知,并且更改检测不会运行。

<!-- Not updated when input control edited. -->
<app-node [node]="rootNode | async"></app-node>

我无法记住我在哪里阅读它,但如果某个组件更新了它自己的数据绑定属性,那么认为更改检测并不是必需的。但是,在此示例中,header.component绑定到节点的属性 - 因此视图{{ node.title }}未更新。为了更清楚,我已在header.component添加了一些评论:

@Component({
    selector: 'node-header',
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HeaderComponent implements OnInit {
    @Input() node: Node;
    @Input() headerForm: FormGroup;

    constructor(private fb: FormBuilder) {}

    ngOnInit() {
        this.headerForm = this.fb.group({
            // Binds to property of node.
            // {{node.title}} won't update even thought it's "local".
            title: [this.node.title]
        });
    }
}

我可以在此处做些什么来确保在用户进行修改时立即更新视图,并且稍后将更改推送到ngrx/store

0 个答案:

没有答案