2016-09-09 10 views
2

Ich habe meine Angular2 RC5-Anwendung auf RC6 aktualisiert. Ich habe einige benutzerdefinierte Formularsteuerelemente basierend auf this Tutorial von Thoughttram entwickelt.Angular2- RC6 Custom Form Controls funktioniert nicht

Alles funktionierte bis RC5, aber nach dem Update funktioniert die Validierung nicht mehr, nach ein wenig Nachforschung fand ich heraus, dass der Wert des Steuerelements nicht im zugehörigen Modell widergespiegelt wird.

Sie können die Original-Plombe aus Thoughttrams Tutorial here finden.

Um das Problem zu aktualisieren, um die Versionsinformationen in systemjs.config.js Datei von

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'; 

zu

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

zu reproduzieren Nachdem die Version, die Sie sehen, aktualisieren wird, dass der Steuerwert nicht aktualisiert wird, und aufgrund dieser die Validierung funktioniert nicht.

Wenn ich jedoch die eckige Version auf @2.0.0-rc.6 aktualisiere und die Formularversion intakt halte, d. H. @0.3.0, funktioniert es.

UPDATE 1:-Code für die Komponente

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); 
    } 
} 

Hauptmodul wie folgt aussieht:

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 {} 

und ich bin die Komponente in meinem app.component wie

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 
    }); 
    } 

} 
mit

Update 2: Ich habe dieses Problem auf Github gemeldet here

Antwort

0

Eine optionale Funktion registerOnChange() wurde in RC.6 für Validator-Direktiven eingeführt, und es existiert bereits eine Funktion mit demselben Namen in controlValueAccessor, die zu Konflikten führte und registerOnChange in meiner Komponente wurde zweimal aufgerufen.

Dies wurde unter der issue behoben.

Empfohlene vorübergehende Lösung ist

@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

Vielen Dank für die Aktualisierung Ihrer Quelle. Ich habe eine Kontrolle, die im Wesentlichen tut, was Sie hier auch tun:

Dies ist die untergeordnete Komponente Spinner:

@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 = "(%)"; 
    } 
    } 

Die 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> 

Die übergeordnete Komponente 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); 
     } 

Das alles funktioniert perfekt auf RC6. Hoffe das hilft dir dein Problem zu lösen.

+0

Wie man sehen kann ich keine veraltete Sache im Quellcode bin mit zur Verfügung gestellt. Es ist also ein anderes Problem, glaube ich. –

+0

Hier gibt es einen Unterschied. Meine Komponente ist ein benutzerdefiniertes Formularsteuerelement, das basierend auf dem Wert ein Formular gültig/ungültig machen kann. In diesem Fall schreiben Sie eine benutzerdefinierte Komponente. Das Problem, dem ich gegenüberstehe, wird nur angezeigt, wenn Sie ein benutzerdefiniertes Formularsteuerelement schreiben. Der Link zu den benutzerdefinierten Formularsteuerelementen ist http://blog.thoughttram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html –

+0

Okay ... aber ich sehe nicht die Unterscheidung zwischen den beiden. Ich erlaube nur gültige Werte in der Kindkomponente, so dass ihre Ausgabe immer gültig ist. –

Verwandte Themen