Пользовательские элементы управления Angular2 - RC6 не работают



Я обновил свое приложение Angular2 RC5 до RC6. Я разработал некоторые пользовательские элементы управления формами, основанные наэтом учебнике из Thoughtram.



Все работало до RC5, однако после обновления проверка больше не работает после небольшого исследования я обнаружил, что значение элемента управления не отражается в соответствующей модели.



Вы можете найти оригинальный плунжер из учебника Thoughtram's tutorialздесь .



Чтобы воспроизвести обновление проблемы информация о версии в файле systemjs.config.js из файла



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


To



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


После обновления версии вы увидите, что значение элемента управления не обновляется и из-за этого проверка не работает.



Однако, если я обновлю угловую версию до @2.0.0-rc.6 и сохраню версию форм неповрежденной, т. е. @0.3.0, это сработает.



Обновление 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
});
}

}


Update 2 : я сообщил об этой проблеме на Github здесь

590   2  

2 ответов:

Спасибо за обновление вашего источника. У меня есть контроль, который делает по существу то же, что и вы здесь:

Это дочерний компонент 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 = "(%)";
    }
  }

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. Надеюсь, это поможет вам решить вашу проблему.

В RC была введена необязательная функция registerOnChange ().6 для директив validator и уже существует функция с тем же именем в controlValueAccessor, которая вызвала конфликт и registerOnChange в моем компоненте был вызван дважды.

Это было исправлено в рамках вопроса.

Предлагаемый временный обходной путь -

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

  //.....
}

Comments

    Ничего не найдено.