2016-09-09 13 views
2

私はAng6のRC5アプリケーションをRC6にアップデートしました。私はThoughtramからthisチュートリアルに基づいていくつかのカスタムフォームコントロールを開発しました。Angular2-RC6カスタムフォームコントロールが動作しない

すべてがRC5まで機能していましたが、更新後に少しの調査の後に検証がもう機能しなくなりました。コントロールの値が関連するモデルに反映されていないことがわかりました。

Thoughtramのチュートリアルhereから元のプランカーを見つけることができます。問題は、バージョン後

var ngVer = '@2.0.0-rc.6'; 
var routerVer = '@3.0.0-rc.2'; 
var formsVer = '@2.0.0-rc.6'; 

var ngVer = '@2.0.0-rc.5'; 
var routerVer = '@3.0.0-rc.1'; 
var formsVer = '@0.3.0'; 
var routerDeprecatedVer = '@2.0.0-rc.2'; 

からsystemjs.config.jsファイル内のバージョン情報を更新再現する

は、あなたがコントロール値が更新されていないことを確認し、これに起因します更新します検証は機能しません。

ただし、角度のバージョンを@2.0.0-rc.6に更新し、フォームのバージョンをそのまま@0.3.0のままにしておくと動作します。

UPDATE 1:コードコンポーネントの

import { Component, OnInit, forwardRef, Input, OnChanges } from '@angular/core'; 
import { FormControl, ControlValueAccessor, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; 


export function createCounterRangeValidator(maxValue, minValue) { 
    return (c: FormControl) => { 
    let err = { 
     rangeError: { 
     given: c.value, 
     max: maxValue || 10, 
     min: minValue || 0 
     } 
    }; 

    return (c.value > +maxValue || c.value < +minValue) ? err: null; 
    } 
} 

@Component({ 
    selector: 'counter-input', 
    template: ` 
    <button (click)="increase()">+</button> {{counterValue}} <button (click)="decrease()">-</button> 
    `, 
    providers: [ 
    { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => CounterInputComponent), multi: true }, 
    { provide: NG_VALIDATORS, useExisting: forwardRef(() => CounterInputComponent), multi: true } 
    ] 
}) 
export class CounterInputComponent implements ControlValueAccessor, OnChanges { 

    propagateChange:any =() => {}; 
    validateFn:any =() => {}; 

    @Input('counterValue') _counterValue = 0; 
    @Input() counterRangeMax; 
    @Input() counterRangeMin; 

    get counterValue() { 
    return this._counterValue; 
    } 

    set counterValue(val) { 
    this._counterValue = val; 
    this.propagateChange(val); 
    } 

    ngOnChanges(inputs) { 
    if (inputs.counterRangeMax || inputs.counterRangeMin) { 
     this.validateFn = createCounterRangeValidator(this.counterRangeMax, this.counterRangeMin); 
    } 
    } 

    writeValue(value) { 
    if (value) { 
     this.counterValue = value; 
    } 
    } 

    registerOnChange(fn) { 
    this.propagateChange = fn; 
    } 

    registerOnTouched() {} 

    increase() { 
    this.counterValue++; 
    } 

    decrease() { 
    this.counterValue--; 
    } 

    validate(c: FormControl) { 
    return this.validateFn(c); 
    } 
} 

メインモジュールは次のようになりますされています

import { NgModule } from '@angular/core'; 
import { BrowserModule } from '@angular/platform-browser'; 
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 
import { AppComponent } from './app.component'; 
import { CounterInputComponent } from './counter-input.component.ts'; 

@NgModule({ 
    imports: [BrowserModule, FormsModule, ReactiveFormsModule], 
    declarations: [AppComponent, CounterInputComponent], 
    bootstrap: [AppComponent] 
}) 
export class AppModule {} 

と私は

import { Component } from '@angular/core'; 
import { FormBuilder, FormGroup } from '@angular/forms'; 
import { createCounterRangeValidator } from './counter-input.component'; 

@Component({ 
    selector: 'my-app', 
    template: ` 
    <h2>Inside Form</h2> 
    <div> 
     <label>Change min value:</label> 
     <input [(ngModel)]="minValue"> 
    </div> 
    <div> 
     <label>Change max value:</label> 
     <input [(ngModel)]="maxValue"> 
    </div> 
    <form [formGroup]="form"> 
     <p>Control value: {{form.controls.counter.value}}</p> 
     <p>Min Value: {{minValue}}</p> 
     <p>Max Value: {{maxValue}}</p> 
     <p>Form Value:</p> 
     <pre>{{ form.value | json }}</pre> 

     <counter-input 
     formControlName="counter" 
     [counterRangeMax]="maxValue" 
     [counterRangeMin]="minValue" 
     [counterValue]="50" 
     ></counter-input> 
    </form> 

    <p *ngIf="!form.valid">Form is invalid!</p> 


    <h2>Standalone</h2> 
    <counter-input 
     counterMinValue="0" 
     counterMaxValue="3" 
     [counterValue]="counterValue"></counter-input> 
    ` 
}) 
export class AppComponent { 

    form:FormGroup; 
    counterValue = 3; 
    minValue = 0; 
    maxValue = 12; 

    constructor(private fb: FormBuilder) {} 

    ngOnInit() { 
    this.form = this.fb.group({ 
     counter: this.counterValue 
    }); 
    } 

} 
ように私のapp.componentでコンポーネントを使用しています

更新2:Githubでこの問題を報告しましたhere

答えて

0

オプションのregisterOnChange()関数がバリデータディレクティブ用にRC.6で導入されました.controlValueAccessorに同じ名前の関数が存在し、競合が発生し、コンポーネントのregisterOnChangeが2回呼び出されました。

これはissueで修正されています。あなたは、私が提供されたソースコード内の任意の非推奨のものを使用していない見ることができるように

推奨一時的な回避策は

@Component({ 
    ... 
    ... 
}) 
export class CounterInputComponent implements ControlValueAccessor, OnChanges { 

    isPropagate: boolean = false; 

    /*Rest of the class implementation 
    ... 
    ... 
    */ 

    registerOnChange(fn) { 
    if (this.isPropagate) { 
     return; 
    } 

    this.propagateChange = fn; 
    this.isPropagate = true; 
    } 

    //..... 
} 
0

ソースを更新していただきありがとうございます。

@Component({ 
    selector: 'kg-spinner', 
    templateUrl: './app/shared/numberSpinner/kgSpinner.component.html', 
    styleUrls: ['./app/shared/numberSpinner/kgSpinner.component.css'] 
}) 

export class KgSpinnerComponent implements OnInit { 
    @Input('startValue') curValue: number; 
    @Input() range: number[]; 
    @Input() increment: number; 
    @Input() spinName; 
    @Input() precision: number; 
    @Input() theme: string; 

    @Output() onChanged = new EventEmitter<SpinnerReturn>(); 

    lowerLimit: number; 
    upperLimit: number; 
    name: string; 
    curTheme: Theme; 
    errorMessage: string; 
    sr: SpinnerReturn; 
    appPageHeaderDivStyle: {}; 
    unit: string = "(g)"; 

    constructor(private ts: ThemeService) { 
    this.sr = new SpinnerReturn(); 
    } 

    ngOnInit() { 
    this.lowerLimit = this.range[0]; 
    this.upperLimit = this.range[1]; 
    this.appPageHeaderDivStyle = this.ts.getAppPageHeaderDivStyle(); 
    if(this.spinName === "carbGoal") { 
     this.unit = "(g)"; 
    } else if (this.spinName === "proteinGoal") { 
     this.unit = "(g)"; 
    } else { 
     this.unit = "(%)"; 
    } 
    } 

HTMLは:

<div class="ui-grid-col-8 spinnerMargin"> 
         <kg-spinner spinName="proteinGoal" [range]=[.6,1.2] [increment]=.1 [startValue]=.6 [precision]=1 (onChanged)="onChanged($event)"></kg-spinner> 
        </div> 

親コンポーネントonChangedイベント:

これは、子コンポーネントのスピナーがある:私はあなたにも、ここで何をやっている、本質的にないコントロールを持っています

onChanged(sr: SpinnerReturn) { 
     if (sr.spinName === "carbGoal") { 
      (<FormControl>this.macroForm.controls['carbGoal']).setValue(sr.spinValue); 
     } else if (sr.spinName === "proteinGoal") { 
      (<FormControl>this.macroForm.controls['proteinGoal']).setValue(sr.spinValue); 
     } else if (sr.spinName === "calorieDifference") { 
      (<FormControl>this.macroForm.controls['calorieDifference']).setValue(sr.spinValue); 
     } 

これはすべてRC6で完全に機能します。これがあなたの問題解決に役立つことを願っています。

+0

です。だから私は信じている他のいくつかの問題です。 –

+0

ここに違いがあります。私のコンポーネントは、値に基づいてフォームを有効/無効にできるカスタムフォームコントロールです。あなたのケースでは、カスタムコンポーネントを作成しています。私が直面する問題は、カスタムフォームコントロールを作成する場合にのみ表示されます。カスタムフォームコントロールへのリンクはhttp://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html –

+0

ですが、表示されません両者の差別化。子コンポーネントで有効な値のみを許可するので、出力は常に有効です。 –

関連する問題