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

Angular 使用@Input FormGroups进行OnPush更改检测,angular,angular2-forms,angular2-changedetection,ngrx-store,Angular,Angular2 Forms,Angular2 Changedetection,Ngrx Store,想象一下Angular 2应用程序中的以下组件层次结构 app.component └── node.component ├── header.component ├── body.component └── footer.component 应用程序将呈现一个节点树。在ngrx/store中有一个“根”节点来反映树的状态 app.component获取保存在ngrx/store中的AppState的“切片”,即根节点上可观察到的 export class AppCom

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

app.component
└── node.component
    ├── header.component
    ├── body.component
    └── footer.component
应用程序将呈现一个节点树。在
ngrx/store
中有一个“根”节点来反映树的状态

app.component
获取保存在
ngrx/store
中的
AppState
的“切片”,即根节点上可观察到的

export class AppComponent {
    rootNode: Observable<Node>;

    constructor(private readonly store: Store<AppState>) {
        this.rootNode = this.store.select(state => state.nodes);
    }
}
node.component
节点作为
Input()
接收,并使用三个组件呈现它:
header.component
body.component
footer.component

@Component({
    selector: 'app-node',
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NodeComponent {
    @Input() node: Node;
    constructor() {}
}
注意,
node.component
视图不使用
async
管道,因为它不是呈现一个
可观察的
,而是一个普通的节点对象:

<node-header [node]="node"></node-header>
<node-body [node]="node"></node-body>
<node-footer [node]="node"></node-footer>
由于
header.component
body.component
footer.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]
        });
    }
}
@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]
        });
    }
}
FormBuilder
创建一个
FormGroup
,并绑定到从
@Input()
接收的节点的
title
属性。
将呈现表单控件以进行编辑,以及值:

<div [formGroup]="headerForm">
    <input formControlName="title"name="title">
</div>
<p>Title {{ node.title }}</p>
我不记得在哪里读到过它,但我认为如果组件更新了它(自己的)数据绑定属性,就不需要进行更改检测。但是,在本例中,
header.component
绑定到节点的属性,因此,
{{node.title}}
视图不会更新。为了更清楚,我在
标题中添加了一些注释

@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]
        });
    }
}
@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]
        });
    }
}

我可以在这里做些什么来确保在用户进行编辑时立即更新视图,并且只有在以后,当您在输入中键入您实际上正在从表单组更改表单控件“title”中的值时,才将更改推送到
ngrx/store

。绑定到node.title显示的是来自state的对象,因此我认为它可以按预期工作。如果将模板绑定到headerForm的值,它应该在键入时更新。类似于{{headerForm.controls.title.value}
@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]
        });
    }
}