父组件和指令之间的Angular2 2向数据绑定
Angular2 2-way databinding between parent component and directive
见下方更新
仍在玩 Angular2 Beta,我正在尝试实现一个 "editor" 组件模板包含包装 Ace 编辑器的指令的场景。因此,"editor" 组件是 Ace 包装器指令的父级,我想从指令中获取代码或将代码设置到其中。
虽然该指令单独工作正常,但当我将它包含在该组件中时,我没有显示任何内容;但是浏览器的控制台中没有显示任何错误。您可以在这个 Plunker 找到 repro:http://plnkr.co/edit/kzclJLIX6hRMWa14A0Pb.
在我的实现中,包装 Ace 编辑器的 ace.directive
指令有一个 text
属性 和一个 textChanged
事件。
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;
private settingText : boolean;
public textChanged: EventEmitter<string>;
set text(s: string) {
let sOld = this.editor.getValue();
if (sOld === s) return;
this.settingText = true;
this.editor.setValue(s);
this.editor.clearSelection();
this.editor.focus();
this.settingText = false;
}
constructor(elementRef: ElementRef) {
var dir = this;
this.textChanged = new EventEmitter<string>();
let el = elementRef.nativeElement;
this.editor = ace.edit(el);
this.editor.on("change", (e) => {
if (dir.settingText) return;
dir.textChanged.next(dir.editor.getValue());
});
}
}
editor.component
组件使用指令:它有一个 xml
属性 代表正在编辑的 XML 代码。其模板包含如下指令:
<ace-editor id="editor" [text]="xml" (textChanged)="onXmlChanged()"></ace-editor>
即指令的 text
属性 绑定到父组件的 xml
属性,指令的 textChanged
事件由父级处理
onXmlChanged
函数。
这是双向数据绑定,据我所知,我也可以尝试:
<ace-editor id="editor" [(ngModel)]="xml"></ace-editor>
这里是小编的代码:
import {Component,EventEmitter} from "angular2/core";
import {AceDirective} from "./ace.directive";
@Component({
selector: "mit-editor",
directives: [AceDirective],
template: `<div>
<ace-editor id="editor" [text]="xml" (textChanged)="onXmlChanged()"></ace-editor>
</div>
`,
inputs: [
"xml"
]
})
export class EditorComponent {
public xml: string;
constructor() {
this.xml = "";
}
public onXmlChanged(xml: string) {
this.xml = xml;
}
}
更新 #1
出于某种原因,Plunker 不会转换和加载我的 .ts 文件而不是预先存在的文件,所以我继续在本地进行故障排除。
至于问题,我发现我必须将 $event
参数添加到模板中的调用中(请参阅我的评论)。我的指令现在是:
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);
});
}
}
编辑器组件模板包含如下指令:
<ace-editor id="editor" [text]="xml" (textChanged)="onXmlChanged($event)"></ace-editor>
无论如何,请注意,如果我现在尝试以编程方式设置编辑器的组件 xml
属性,Angular 开始并无限循环,因为更改会触发 ace 编辑器上的事件发出再次设置 xml
属性 的事件,依此类推。可能只是我做错了什么,但目前我不得不在代码中使用这个 hack,当然我不喜欢它:):
// ...
export class EditorComponent {
private _xml: string;
private _changeFrozenCount: number;
public set xml(s: string) {
this._xml = s;
}
public get xml() : string {
return this._xml;
}
constructor(private editorService: EditorService, private xmlService: XmlService) {
this._xml = "";
}
public onXmlChanged(xml: string) {
if (this._changeFrozenCount > 0) {
this._changeFrozenCount--;
return;
}
this._xml = xml;
}
public changeXml() {
this._changeFrozenCount = 1;
this._xml = "<sample>Hello</sample>"
}
}
您忘记添加了
directives: [EditorComponent]
在您的 app.ts 文件中。当前 directives
数组在您的 plunker 中为空 ([]
)。只需进行此更改即可生效,如果您设置 onXmlChanged($event)
它甚至不会在您在编辑器中键入时出错 :)
见下方更新
仍在玩 Angular2 Beta,我正在尝试实现一个 "editor" 组件模板包含包装 Ace 编辑器的指令的场景。因此,"editor" 组件是 Ace 包装器指令的父级,我想从指令中获取代码或将代码设置到其中。
虽然该指令单独工作正常,但当我将它包含在该组件中时,我没有显示任何内容;但是浏览器的控制台中没有显示任何错误。您可以在这个 Plunker 找到 repro:http://plnkr.co/edit/kzclJLIX6hRMWa14A0Pb.
在我的实现中,包装 Ace 编辑器的 ace.directive
指令有一个 text
属性 和一个 textChanged
事件。
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;
private settingText : boolean;
public textChanged: EventEmitter<string>;
set text(s: string) {
let sOld = this.editor.getValue();
if (sOld === s) return;
this.settingText = true;
this.editor.setValue(s);
this.editor.clearSelection();
this.editor.focus();
this.settingText = false;
}
constructor(elementRef: ElementRef) {
var dir = this;
this.textChanged = new EventEmitter<string>();
let el = elementRef.nativeElement;
this.editor = ace.edit(el);
this.editor.on("change", (e) => {
if (dir.settingText) return;
dir.textChanged.next(dir.editor.getValue());
});
}
}
editor.component
组件使用指令:它有一个 xml
属性 代表正在编辑的 XML 代码。其模板包含如下指令:
<ace-editor id="editor" [text]="xml" (textChanged)="onXmlChanged()"></ace-editor>
即指令的 text
属性 绑定到父组件的 xml
属性,指令的 textChanged
事件由父级处理
onXmlChanged
函数。
这是双向数据绑定,据我所知,我也可以尝试:
<ace-editor id="editor" [(ngModel)]="xml"></ace-editor>
这里是小编的代码:
import {Component,EventEmitter} from "angular2/core";
import {AceDirective} from "./ace.directive";
@Component({
selector: "mit-editor",
directives: [AceDirective],
template: `<div>
<ace-editor id="editor" [text]="xml" (textChanged)="onXmlChanged()"></ace-editor>
</div>
`,
inputs: [
"xml"
]
})
export class EditorComponent {
public xml: string;
constructor() {
this.xml = "";
}
public onXmlChanged(xml: string) {
this.xml = xml;
}
}
更新 #1 出于某种原因,Plunker 不会转换和加载我的 .ts 文件而不是预先存在的文件,所以我继续在本地进行故障排除。
至于问题,我发现我必须将 $event
参数添加到模板中的调用中(请参阅我的评论)。我的指令现在是:
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);
});
}
}
编辑器组件模板包含如下指令:
<ace-editor id="editor" [text]="xml" (textChanged)="onXmlChanged($event)"></ace-editor>
无论如何,请注意,如果我现在尝试以编程方式设置编辑器的组件 xml
属性,Angular 开始并无限循环,因为更改会触发 ace 编辑器上的事件发出再次设置 xml
属性 的事件,依此类推。可能只是我做错了什么,但目前我不得不在代码中使用这个 hack,当然我不喜欢它:):
// ...
export class EditorComponent {
private _xml: string;
private _changeFrozenCount: number;
public set xml(s: string) {
this._xml = s;
}
public get xml() : string {
return this._xml;
}
constructor(private editorService: EditorService, private xmlService: XmlService) {
this._xml = "";
}
public onXmlChanged(xml: string) {
if (this._changeFrozenCount > 0) {
this._changeFrozenCount--;
return;
}
this._xml = xml;
}
public changeXml() {
this._changeFrozenCount = 1;
this._xml = "<sample>Hello</sample>"
}
}
您忘记添加了
directives: [EditorComponent]
在您的 app.ts 文件中。当前 directives
数组在您的 plunker 中为空 ([]
)。只需进行此更改即可生效,如果您设置 onXmlChanged($event)
它甚至不会在您在编辑器中键入时出错 :)