2016-05-16 26 views
2

我在跟隨下面的文章,並試圖在與ngModel和ngControl集成的角度2中實現自定義控件。當爲自定義控件實現值訪問器時未從事件中的模型獲取更新值

文章:http://almerosteyn.com/2016/04/linkup-custom-control-to-ngcontrol-ngmodel

,但我有一個很難的時間來弄清楚如何發射事件時獲得更新的模型值。它似乎在事件更新之前使用模型。

下面是一個例子的plunker:

https://plnkr.co/edit/ixK6UxhhWZnkFyKfbgky

我在做什麼錯?

main.ts

import {bootstrap} from '@angular/platform-browser-dynamic'; 
import {App} from './app'; 

bootstrap(App, []) 
    .catch(err => console.error(err)); 

app.ts

import {Component} from '@angular/core' 
import {FORM_DIRECTIVES} from "@angular/common"; 
import {CustomInput} from './custom-input.component' 

@Component({ 
    selector: 'my-app', 
    providers: [], 
    template: ` 
    <form (ngSubmit)="onSave()" #demoForm="ngForm"> 

    <div class="row info-row"> 
    <span class="col-xs-12"> 
    <p><span class="boldspan">Form data:</span>{{demoForm.value | json}}</p> 
    <p><span class="boldspan">Model data:</span> {{dataModel}}</p> 
    </span> 
    </div> 

    <custom-input ngControl="someValue" ref-input (onKeyDown)="onKeyDown(input)" [(ngModel)]="dataModel">Enter data:</custom-input> 

    </form> 
    `, 
    directives: [CustomInput, FORM_DIRECTIVES] 
}) 
export class App { 
    dataModel: string = ''; 

    onKeyDown(event){ 
    console.log(event._value); 
    console.log(this.dataModel); 
    } 
} 

定製input.component.ts

import {Component, Provider, forwardRef, Input, Output, EventEmitter} from "@angular/core"; 
import {ControlValueAccessor, NG_VALUE_ACCESSOR, CORE_DIRECTIVES} from "@angular/common"; 

const noop =() => {}; 

const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR = new Provider(
    NG_VALUE_ACCESSOR, { 
    useExisting: forwardRef(() => CustomInput), 
    multi: true 
    }); 

@Component({ 
    selector: 'custom-input', 
    template: ` 
     <div class="form-group"> 
     <label><ng-content></ng-content> 
      <input class="form-control" [(ngModel)]="value" (keydown)="onKeyDownEvent($event)" (blur)="onTouched()"> 
     </label> 
     </div> 
    `, 
    directives: [CORE_DIRECTIVES], 
    providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR] 
}) 
export class CustomInput implements ControlValueAccessor{ 

    @Output() onKeyDown: EventEmitter<any> = new EventEmitter(); 

    //The internal data model 
    private _value: any = ''; 

    //Placeholders for the callbacks 
    private _onTouchedCallback: (_:any) => void = noop; 

    private _onChangeCallback: (_:any) => void = noop; 

    //get accessor 
    get value(): any { return this._value; }; 

    //set accessor including call the onchange callback 
    set value(v: any) { 
     if (v !== this._value) { 
     this._value = v; 
     this._onChangeCallback(v); 
     } 
    } 

    //Set touched on blur 
    onTouched(){ 
     this._onTouchedCallback(); 
    } 

    //From ControlValueAccessor interface 
    writeValue(value: any) { 
     this._value = value; 
    } 

    //From ControlValueAccessor interface 
    registerOnChange(fn: any) { 
     this._onChangeCallback = fn; 
    } 

    //From ControlValueAccessor interface 
    registerOnTouched(fn: any) { 
     this._onTouchedCallback = fn; 
    } 

    onKeyDownEvent(event){ 
     this.onKeyDown.emit(event); 
    } 

} 

回答

0

我認爲親瑕疵是你混合自定義輸出和註冊回調。在這種情況下,不需要定製輸出。

你可以充分利用CustomInput組件內的ngModelChange事件調用_onChangeCallback回調:

@Component({ 
    selector: 'custom-input', 
    template: ` 
    <div class="form-group"> 
     <label><ng-content></ng-content> 
     <input class="form-control" [(ngModel)]="value" 
      (ngModelChange)="onModelChange($event)" 
      (keydown)="onKeyDownEvent($event)" 
      (blur)="onTouched()"> 
     </label> 
    </div> 
`, 
(...) 
export class CustomInput implements ControlValueAccessor { 
    (...) 

    onModelChange(value) { 
    this.value = value; 
    this._onChangeCallback(value); 
    } 
} 

在這種情況下,你的getter和setter是沒有必要了。

本文也可能你感興趣(節 「NgModel兼容設備」):

+0

謝謝你的信息。我不知道ngModelChange和一個偉大的文章btw。我已經嘗試過你提出的,這裏有一個新的[plunkr](https://plnkr.co/edit/95tudMnWDt1JMVOo3U4U?p=preview),但奇怪的是,一旦我刪除了get和set,它不再綁定初始值。你說過我混淆了一些東西,但是如果沒有這樣做,怎麼可能在組件外部獲得更新的模型呢? – rmarchiori

相關問題