我正在尝试使用Angular 2 Forms,但我不想使用输入,而是想使用可编辑的div.
这有效:
- <input type="text" [(ngModel)]="value">
但这会引发错误:
- <div contentEditable="true" [(ngModel)]="value"></div>
TypeError: setting a property that has only a getter
有没有办法在Angular Forms中使用div?我不想使用输入或textarea
不是开箱即用..
ngModel只能在支持它的元素上访问!
您可以创建指令或自定义输入组件.
无论如何,它必须实现此接口ControlValueAccessor.
指示:
工作演示:https://plnkr.co/edit/12vAEFf2OBS3ERu9fhwk?p=preview
- import {Directive,Component,NgModule,forwardRef,ViewChild,ElementRef,HostListener,Renderer} from '@angular/core'
- import {BrowserModule} from '@angular/platform-browser'
- import { FormsModule,ControlValueAccessor,NG_VALUE_ACCESSOR } from '@angular/forms';
- @Directive({
- selector: 'div[contentEditable]',providers: [
- {
- provide: NG_VALUE_ACCESSOR,useExisting: forwardRef(() => EditableDivDirective),multi: true
- }
- ]
- })
- export class EditableDivDirective implements ControlValueAccessor {
- constructor(private _elRef: ElementRef,private _renderer: Renderer) { }
- onChange() {
- if (this._onChange) {
- this._onChange(this._elRef.nativeElement.innerText);
- }
- }
- @HostListener('keyup',['$event'])
- keyup(event: any) {
- this.onChange();
- }
- // ControlValueAccessor implementation
- // ====================================
- private _onChange = (_) => { }; // call it if your value changed..
- private _onTouched = () => { }; // call it "on blur" ..
- // will be called if a values comes in via ngModule !
- writeValue(val: any) {
- if (!val) val = '';
- this._renderer.setElementProperty(this._elRef.nativeElement,'innerText',val);
- }
- registerOnChange(fn: (_: any) => void): void { this._onChange = fn; }
- registerOnTouched(fn: () => void): void { this._onTouched = fn; }
- }
- @Component({
- selector: 'my-app',template: `
- <div>
- <h2>Hello {{name}}</h2>
- <div contentEditable="true" [(ngModel)]="name">test test test</div>
- </div>
- `,})
- export class App {
- name:string;
- constructor() {
- this.name = 'Angular2'
- }
- }
- @NgModule({
- imports: [ BrowserModule,FormsModule ],declarations: [ App,EditableDivDirective ],bootstrap: [ App ]
- })
- export class AppModule {}
零件:
查看工作演示:https://plnkr.co/edit/XMSTrWSe3gN9iwVTBukz?p=preview
- import {Component,ElementRef} from '@angular/core'
- import {BrowserModule} from '@angular/platform-browser'
- import { FormsModule,NG_VALUE_ACCESSOR } from '@angular/forms';
- @Component({
- selector: 'my-name-input',template: `
- <div>
- <label>first name</label>
- <div #firstName contentEditable="true" (keyup)="onChange()">{{this._firstName}}</div>
- <br />
- <label>last name</label><input [(ngModel)]="_lastName" (ngModelChange)="onChange()" />
- </div>
- `,providers: [ // IMPORTANT !!
- {
- provide: NG_VALUE_ACCESSOR,useExisting: forwardRef(() => MyCompleteNameInputComponent),multi: true
- }
- ]
- })
- export class MyCompleteNameInputComponent implements ControlValueAccessor {
- @ViewChild('firstName') editableDiv: ElementRef;
- private _firstName: string = '';
- private _lastName: string = '';
- onChange() {
- this._firstName = this.editableDiv.nativeElement.innerText;
- if (this._onChange) {
- this._onChange(this._firstName + ' ' + this._lastName);
- }
- }
- // ControlValueAccessor implementation
- // ====================================
- private _onChange = (_) => { }; // call it if your value changed..
- private _onTouched = () => { }; // call it "on blur" ..
- // will be called if a values comes in via ngModule !
- writeValue(val: any) {
- if (!val || !val.split) val = '';
- let splitted = val.split(' ');
- this._firstName = splitted[0] || '';
- this._lastName = splitted[1] || '';
- }
- registerOnChange(fn: (_: any) => void): void { this._onChange = fn; }
- registerOnTouched(fn: () => void): void { this._onTouched = fn; }
- }
- @Component({
- selector: 'my-app',template: `
- <div>
- <h2>Hello {{name}}</h2>
- <my-name-input [(ngModel)]="name"></my-name-input>
- </div>
- `,MyCompleteNameInputComponent ],bootstrap: [ App ]
- })
- export class AppModule {}