2016-09-23 61 views
7

我正在尝试使用Angular 2 Forms,而不是使用input我想使用可编辑divAngular 2格式与contentEditable div和ngModel支持

这工作:

<input type="text" [(ngModel)]="value"> 

但是,这将引发错误:

<div contentEditable="true" [(ngModel)]="value"></div> 

TypeError: setting a property that has only a getter

有没有使用分度角形式的方法吗?我不想用输入或textarea的

回答

8

不开箱..

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, NgModule, forwardRef, ViewChild, ElementRef} from '@angular/core' 
import {BrowserModule} from '@angular/platform-browser' 
import { FormsModule, ControlValueAccessor, 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> 
    `, 
}) 
export class App { 
    name:string; 
    constructor() { 
    this.name = 'Angular2' 
    } 
} 

@NgModule({ 
    imports: [ BrowserModule, FormsModule ], 
    declarations: [ App, MyCompleteNameInputComponent ], 
    bootstrap: [ App ] 
}) 
export class AppModule {} 
+0

守ld我添加一个例子? :) – mxii

+0

请?我从来没有尝试过这样的事情 –

+0

看到我的更新答案,包括一个工作的重击者。 – mxii