我正试图通过构建一个漂亮的wysiwyg组件来学习angular2,但它的接缝让我现在碰壁了。所以,这是我的代码:
app.component.ts是我用来测试组件的一个表单(我从angular教程中修改了英雄表单):
import {Component} from 'angular2/core';
import {NgForm} from 'angular2/common';
import { Article } from './article';
import {aWysiwygComponent} from './aWysiwyg.component'
@Component({
selector: 'test-form',
templateUrl: 'app/article-form.component.html',
directives: [aWysiwygComponent]
})
export class ArticleFormComponent {
model = new Article(18, 'Dr IQ', 'Chuck Overstreet');
submitted = false;
onSubmit() { this.submitted = true; }
// Reset the form with a new hero AND restore 'pristine' class state
// by toggling 'active' flag which causes the form
// to be removed/re-added in a tick via NgIf
// TODO: Workaround until NgForm has a reset method (#6822)
active = true;
newArticle() {
this.model = new Article(42, '', '');
this.active = false;
setTimeout(()=> this.active=true, 0);
}
}
其html为:
<div class="container">
<div [hidden]="submitted">
<h1>Hero Form</h1>
<form *ngIf="active" (ngSubmit)="onSubmit()" #articleForm="ngForm">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" required
[(ngModel)]="model.name"
ngControl="name" #name="ngForm" >
<div [hidden]="name.valid || name.pristine" class="alert alert-danger">
Name is required
</div>
</div>
<div class="form-group">
<label for="content">Content</label>
<aWysiwyg [(model)]="model.content"></aWysiwyg>
</div>
<button type="submit" class="btn btn-default" [disabled]="!articleForm.form.valid">Submit</button>
<button type="button" class="btn btn-default" (click)="newArticle()">New Article</button>
</form>
</div>
<div [hidden]="!submitted">
<h2>You submitted the following:</h2>
<div class="row">
<div class="col-xs-3">Name</div>
<div class="col-xs-9 pull-left">{{ model.name }}</div>
</div>
<div class="row">
<div class="col-xs-3">Content</div>
<div class="col-xs-9 pull-left">{{ model.content }}</div>
</div>
<br>
<button class="btn btn-default" (click)="submitted=false">Edit</button>
</div>
</div>
这是wysiwyg组件:
import {Component, ViewEncapsulation, Input} from 'angular2/core';
import {ToolbarComponent} from './components/toolbar.component';
import {EditableComponent} from './components/editable.component';
import { NgForm, FORM_PROVIDERS, FORM_DIRECTIVES } from 'angular2/common';
@Component({
selector: 'aWysiwyg',
templateUrl: '../app/templates/editor.html',
styleUrls:['./app/styles/bootstrap.min.css', './app/styles/styles.css', './app/styles/font-awesome.min.css'],
encapsulation: ViewEncapsulation.None,
providers: [FORM_PROVIDERS],
directives: [ToolbarComponent, EditableComponent, FORM_DIRECTIVES]
})
export class aWysiwygComponent {
@Input() model:any;
}
html:
<section class="editor col-sm-24 col-lg-24">
<aToolbar class="row">Loading...</aToolbar>
<aEditable [(model)]="model" class="row">Loading...</aEditable>
</section>
<textarea class="form-control" id="hiddenInput" hidden>{{model}}</textarea>
可编辑区域组件:
import {Component, Input, AfterViewInit} from 'angular2/core';
import { NgForm, FORM_PROVIDERS, FORM_DIRECTIVES } from 'angular2/common';
@Component({
selector: 'aEditable',
templateUrl: './app/templates/editable.html',
providers: [FORM_PROVIDERS],
directives: [FORM_DIRECTIVES]
})
export class EditableComponent implements AfterViewInit {
@Input() model:any;
ngAfterViewInit(){
jQuery('#editable-area').keyup(function(){
jQuery('#hiddenInput').text(jQuery('#editable-area').html())
})
}
}
和html:
<section id="editable">
<div id="editable-area" contenteditable >
{{model}}
</div>
</section>
项目的其余部分只是工具栏的一组组件。现在,问题是,当我提交表单时,我从wysiwyg没有得到任何信息,即使我在其中写内容,我看到内容被复制到textarea
中,它也不会将其与表单的其他部分一起发布。我检查了控制台,没有任何异常,一切看起来都很好。有人看到我做错了什么吗?非常感谢。
如果你想利用双向绑定,你还需要在你的组件中有一个Output
:
@Component({
selector: 'aEditable',
templateUrl: './app/templates/editable.html',
providers: [FORM_PROVIDERS],
directives: [FORM_DIRECTIVES]
})
export class EditableComponent implements AfterViewInit {
@Input() model:any;
// The name is important here (the suffix "Change") to be
// able to use the syntax shortcut: [(model)]
@Output() modelChange:EventEmitter<any> = new EventEmitter();
ngAfterViewInit(){
jQuery('#editable-area').keyup(() => {
let content = jQuery('#editable-area').html();
this.modelChange.emit(content);
jQuery('#hiddenInput').text(content);
});
}
}
此外,您的aEditable
组件符合ngModel
/ngControl
。这意味着它不能参与表单验证及其全局状态。如果您想要/需要此功能,则必须实现自定义值访问器。以下是您的案例示例:
const EDITABLE_VALUE_ACCESSOR = new Provider(NG_VALUE_ACCESSOR, { useExisting: forwardRef(() => EditableComponent), multi: true});
@Component({
selector: 'aEditable',
templateUrl: './app/templates/editable.html',
providers: [FORM_PROVIDERS, EDITABLE_VALUE_ACCESSOR],
directives: [FORM_DIRECTIVES]
})
export class EditableComponent implements ControlValueAccessor {
content:string;
onChange = (_) => {};
onTouched = () => {};
writeValue(value: any): void {
this.content = value;
// write in the DOM
}
ngAfterViewInit(){
jQuery('#editable-area').keyup(() => {
this.content = jQuery('#editable-area').html();
jQuery('#hiddenInput').text(this.content);
this.onChange(content);
});
}
registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
registerOnTouched(fn: () => void): void { this.onTouched = fn; }
}
最后,您可以利用Angular2支持与DOM交互,而不是使用jQuery。例如使用@ViewChild
装饰器:
<section #editable>
<div id=#editableArea contenteditable >
{{model}}
</div>
</section>
在组件中
@ViewChild('editable')
editableElement:ElementRef;
@ViewChild('editableArea')
editableAreaElement:ElementRef;
constructor(private renderer:Renderer) {
}
onAfterViewInit() {
(...)
}
这个关于可编辑内容的问题也可能引起你的兴趣:
- 如何在contenteditable元素中使用ngControl