Angular2:如何正确实现双向数据绑定而不会产生无限循环

时间:2016-01-14 15:37:11

标签: typescript angular

仍在继续我的Angular2(beta 1)新人之旅,我试图了解如何正确实现双向绑定,而不会让我的应用程序陷入无限循环。

请在此Plunker找到样本repro:http://plnkr.co/edit/83NeiUCEpPvYvUXIkl0g。只需运行并单击按钮。

我的情景:

  • 指令包装Ace代码编辑器并公开text属性和textChanged事件。
  • (XML)编辑器组件使用此指令。它应该能够响应底层编辑器中的更改以更新其XML代码,并从其XML代码在基础编辑器中设置新文本。

我的问题是,只要编辑器组件以编程方式设置其xml属性,就会触发底层Ace编辑器的更改,而后者又会触发文本更改事件,而事件又由编辑器组件处理#39; s回调,等等。这会产生无限循环,您可以看到编辑器的文本闪烁。我在这里做错了什么?

以下是该指令的代码:

import {Component,Directive,EventEmitter,ElementRef} from 'angular2/core';
declare var ace: any;

@Directive({
    selector: "ace-editor",
    inputs: [
        "text"
    ],
    outputs: [
        "textChanged"
    ]
})
export class AceDirective { 
    private editor : any;
    public textChanged: EventEmitter<string>;

    set text(s: string) {
        if (s === undefined) return;
        let sOld = this.editor.getValue();
        if (sOld === s) return;        
        this.editor.setValue(s);
        this.editor.clearSelection();
        this.editor.focus();
    }

    get text() {
        return this.editor.getValue();
    }

    constructor(elementRef: ElementRef) {
        var dir = this;
        this.textChanged = new EventEmitter<string>();

        let el = elementRef.nativeElement;
        this.editor = ace.edit(el);
        let session = this.editor.getSession();
        session.setMode("ace/mode/xml");
        session.setUseWrapMode(true);

        this.editor.on("change", (e) => {
            let s = dir.editor.getValue();
            dir.textChanged.next(s);
        });
    }
}

这是编辑器组件:

import {Component,EventEmitter} from "angular2/core";
import {AceDirective} from "./ace.directive";

@Component({
    selector: "my-editor",
    directives: [AceDirective],
    template: `<div style="border:1px solid red">
    <ace-editor id="editor" [text]="xml" (textChanged)="onXmlChanged($event)"></ace-editor>
    </div>
    <div><button (click)="changeXml()">set xml</button></div>`,
    inputs: [
        "xml"
    ]
})
export class EditorComponent { 
    private _xml: string;

    // using a property here so that I can set a breakpoint
    public set xml(s: string) {
        this._xml = s; 
    }
    public get xml() : string {
        return this._xml;
    }

    constructor() {
        this._xml = "";
    }

    public onXmlChanged(xml: string) {
        this._xml = xml;
    }

    // an action which somehow changes the XML content
    public changeXml() {
        this._xml = "<x>abc</x>";
    }
}

1 个答案:

答案 0 :(得分:3)

只需执行[(ngModel)] =&#34;属性&#34;句法。即使它看起来像旧的双向绑定实际上将它分解为两个不同的单向绑定,一个用于输入,一个用于输出,Angular 2处理更改的方式和他在引擎盖下的脏检查周期是什么改变了,不允许你做无限循环。