Angular 2组件:如何处理圆形输入和输出

本杰明·M

现在的情况:

我有一个parent和一个child组件。

parent初始化child使用它的数据@Inputchild当用户使用来编辑数据时通知父项@Output并且由于数据是不可变的,因此child必须将数据与该通知一起发送。

parent得到通知,它会检查提交的数据是否有效,然后将其设置(这将在新的价值传播到其他一些子组件以及)。

问题:

当在中设置新数据时parent,它当然也会将其提供给child刚刚提交数据组件。这将触发childngOnChanges,然后触发UI的重新绘制。

一些背景:

parent有几个不同的child组件,它们都依赖于相同的myItem数据,并可以编辑这些数据,然后通知parent上的变化。


这是代码的简化版本,应该可以显示问题。

父组件:

template:
    <child [input]="myItem" (output)="onMyItemChange($event)">

code:
    ngOnInit() {
        this.myItem = getDataViaHTTP();
    }

    onMyItemChange($event) {
        if($event.myItem.isValid()) {
            this.myItem = $event.myItem;
        }
    }

子组件:

template:
    <input [(ngModel)]="myItem.name" (ngModelChange)="modelChange($event)">

code:
    @Input() input;
    @Output() output = new EventEmitter();

    myItem;

    ngOnChanges(changes) {
        this.myItem = changes.input.currentValue.toMutableJS();
    }

    modelChange($event) {
        this.output.emit(this.myItem.toImmutableJS())
    }

如您所见,该child组件从中获取数据@Input并使其可变。并且在将其发送回之前,parent它将再次变得不可变。


是否有任何模式可以防止这些循环事件?

萧敬腾

如果我们坚持使用双向事件触发器,我想不出办法摆脱困境。特别是有多个孩子。

方法一

我能想到的一种方法是父母和孩子都使用共享数据服务。数据是一劳永逸的,因为各方都在使用相同的数据。

globaldata.service.ts

import { Injectable } from '@angular/core';

interface ShareObj {
  [id: string]: any;
}

@Injectable()
export class GlobalDataService {
  shareObj: ShareObj = {};
}

app.module.ts(假设这是您的根模块)

import { GlobalDataService } from './globaldata.service';
//
// skip ..
//

@NgModule({
  //
  // skip ..
  //

  provider:[GlobalDataService]

})
export class AppModule {}

parent.component.ts(假设非root用户,多个实例,属于app.module的一部分)

template:
    <child [parent]="myId"></child>

code:
    import { GlobalDataService } from './globaldata.service';
    //
    // skip ..
    //

    // use uuid to generate unique id
    private uuid = require('node-uuid');
    myId = this.uuid.v1();

    constructor(private gd: GlobalDataService){
        // This can be string, array or object
        this.gd.shareObj[myId]='data';
    }

child.component.ts

template:
    <input [(ngModel)]="gd.shareObj[parent]">

code:
    import { GlobalDataService } from './globaldata.service';
    //
    // skip ..
    //

    constructor(private gd: GlobalDataService){}

    @Input() parent;

方法2-广播队列

使用RxJ的主题订阅,例如广播队列。我实际上已经创建了一个带有示例的包:

https://github.com/J-Siu/ng2-simple-mq

https://github.com/J-Siu/ng2-simple-mq-example

这个想法:

  1. 父母和所有孩子将订阅同一队列
  2. 在广播到队列时包括发件人ID,如果使用我的软件包,则可以将订阅ID用作发件人ID,因为它是uuid。
  3. 回调将检查发件人ID,如果邮件是来自自身的,则不采取任何操作

父级(假设非root用户,多个实例,属于app.module的一部分)

import {Component, OnInit} from '@angular/core';
import {SimpleMQ} from 'ng2-simple-mq';

template:
    <child [parent]="myId"></child>

code:
  export class SomeComponent implements OnInit {
    title = 'Some Component';

    // use uuid to generate unique id
    private uuid = require('node-uuid');
    myId = this.uuid.v1();
    myItem = {};

    constructor(private smq: SimpleMQ) { }

    ngOnInit() {
        this.smq.subscribe(this.myId, e => this.receiveBroadcast(e));
    }

    broadcast() {

        let msg = {
            id: this.myId,
            msg: 'some messages or object go here'
        };

        // Publish to queue name 'this.myId'
        this.smq.publish(this.myId, msg);
    }

    receiveBroadcast(m) {
        if (m.id !== this.myId) {
            // msg from soneone else, lets do something

            this.myItem = m.msg; // Update local data

            console.log(m.Id + ' received: ' + m.msg);
        }
    }
}

孩子

import {Component, Input, OnInit} from '@angular/core';
import {SimpleMQ} from 'ng2-simple-mq';

template:
<input [(ngModel)]="myItem.name" (ngModelChange)="broadcast()">

code:
  export class SomeComponent implements OnInit {
    title = 'Some Component';

    @Input() parent;
    // use uuid to generate unique id
    private uuid = require('node-uuid');
    myId = this.uuid.v1();

    myItem = {};

    constructor(private smq: SimpleMQ) { }

    ngOnInit() {
        this.smq.subscribe(parent, e => this.receiveBroadcast(e));
    }

    broadcast() {

        let msg = {
            id: this.myId,
            msg: this.myItem // send the whole object
        };

        // Publish to queue name = parent id
        this.smq.publish(parent, msg);
    }

    receiveBroadcast(m) {
        if (m.id !== this.myId) {
            // msg from soneone else, lets do something

            this.myItem = m.msg; // Update local data

            console.log(m.Id + ' received: ' + m.msg);
        }
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

输入的Angular 2组件样式

来自分类Dev

Angular 2组件和CRUD

来自分类Dev

Angular2组件是单向绑定还是输入?

来自分类Dev

RxJS主题和Angular 2组件

来自分类Dev

扩展/装饰Angular 2组件和指令

来自分类Dev

Angular 2组件变量范围和参考

来自分类Dev

如何在Angular 2组件中测试RouteConfig和其他装饰器

来自分类Dev

如何从Angular 2组件调用jstree On函数

来自分类Dev

如何模拟Angular 2组件的JQuery Ajax调用

来自分类Dev

如何使angular2组件ng无效

来自分类Dev

如何模拟Angular 2组件的JQuery Ajax调用

来自分类Dev

如何使angular2组件ng无效

来自分类Dev

如何从Angular 2组件中更改CSS样式

来自分类Dev

Angular 2组件动态名称

来自分类Dev

Angular 2组件未显示

来自分类Dev

Angular 2组件与Portlet

来自分类Dev

Angular 2组件不显示

来自分类Dev

Angular 2组件问题

来自分类Dev

如何处理Angular组件中的错误

来自分类Dev

如何在多个Angular 2项目之间共享Angular 2组件?

来自分类Dev

Angular 2组件和Web组件之间有什么区别?

来自分类Dev

Angular2组件:测试表单输入值更改

来自分类Dev

使用ComponentResolver动态创建Angular 2组件时传递输入

来自分类Dev

Angular2组件:测试表单输入值更改

来自分类Dev

具有双向绑定输入的Angular2组件不会触发更改事件

来自分类Dev

如何在Angular 2组件函数中使用Angular 1指令变量

来自分类Dev

Angular 2组件中的组件不显示?

来自分类Dev

Angular 2组件到组件的通信

来自分类Dev

如何使用ng2-dragula拖放到多个Angular2组件