我正在尝试通过构建一个漂亮的所见即所得组件来学习angular2,但它接缝我现在碰到了一堵砖墙。所以,这是我的代码:
app.component.ts是我用来测试组件的一个表单(我修改了角度教程中的英雄形式):
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
中,它也不会将其发布到其他内容中形式。我检查了控制台,没有例外,一切看起来都很好。谁能看到我做错了什么?谢谢。
答案 0 :(得分:1)
这里有两件事。
如果您想利用双向绑定,您还需要在组件中使用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() {
(...)
}
关于可编辑内容的这个问题也可能让您感兴趣: