угловой пользовательский компонент ввода не обновляется - PullRequest
0 голосов
/ 20 сентября 2018

Я создал пользовательский компонент ввода для раз.Я могу успешно установить начальное значение, полученное [(ngModel)], однако любые изменения в поле ввода не обрабатываются.Чтобы быть более точным: writeValue вызывается изначально, а установщик - нет.

Компонент выглядит следующим образом:

@Component({
  selector: 'app-timepicker',
  templateUrl: './timepicker.component.html',
  styleUrls: ['./timepicker.component.scss'],
  providers: [{provide: MatFormFieldControl, useExisting: forwardRef(() => NexupTimepickerComponent)}]
})
export class NexupTimepickerComponent implements OnDestroy, ControlValueAccessor {

  autofilled: boolean;

  // Subject for the changes on the input
  stateChanges = new Subject<void>();

  // Grouping of the input fields
  parts: FormGroup;

  public _onChange: any;

  constructor(fb: FormBuilder, private fm: FocusMonitor, private elRef: ElementRef<HTMLElement>,
              @Optional() @Self() public ngControl: NgControl
  ) {
    this.parts =  fb.group({
      'hour': '',
      'minute': ''
    });

    // control focus
    fm.monitor(elRef.nativeElement, true).subscribe(origin => {
      this.focused = !!origin;
      this.stateChanges.next();
    });

    this._onChange = (_: any) => {
    };
    if (this.ngControl) {
      this.ngControl.valueAccessor = this;
    }
  }

  // value
  @Input()
  get value(): Time | null {
    console.log('Getting value');
    const n = this.parts.value;
    if (n.hour.length === 2 && n.minute.length === 2) {
      return new Time(n.hour, n.minute);
    }
    return null;
  }

  set value(time: Time | null) {
    console.log('Setting value to: ', time);
    time = time || new Time('', '');
    this.parts.setValue({hour: time.hour, minute: time.minute});
    this.stateChanges.next();
  }

  ngOnDestroy() {
    this.stateChanges.complete();
    this.fm.stopMonitoring(this.elRef.nativeElement);
  }

  registerOnChange(fn: any): void {
    console.log('registered');
    this._onChange = fn;
  }

  registerOnTouched(fn: any): void {
  }

  setDisabledState(isDisabled: boolean): void {
  }

  writeValue(value: any): void {
    console.log('received value: ', value);
    if ((value !== this.parts.getRawValue()) && value) {
      console.log('writing value to: ', value);
      this.parts.setValue({hour: value.hour, minute: value.minute});
      console.log('new value: ', this.parts.getRawValue());
    }
  }

}

HTML в родительском компоненте выглядит так:

<mat-form-field appearance="outline">
          <mat-label>End Time</mat-label>
          <app-timepicker [required]="true"
            [(ngModel)]="endTimeObject" #endTime="ngModel" name="endTime" ngDefaultControl>
          </app-timepicker>
</mat-form-field>

1 Ответ

0 голосов
/ 21 сентября 2018

Если setter: set value не вызывается, это обычно потому, что у вас нет значения «value», вы должны были сделать что-то вроде this.value = "...";

Для этого и для большего контроля я обычно добавляю [formControl] =" myControl "на внутренний вход моего компонента (если он у меня есть :)) и делаю что-то подобное вкомпонент:

myControl = new FormControl();

this.myControl.onStatusChange.subscribe( (newValue) => {
  this.value = newValue;
});

Кроме того, будет нормально, что [(ngModel)] не будет обновляться до текущей даты, потому что вы никогда не вызываете обратный вызов this._onChange ().

Метод registerOnChage дает вам обратный вызов, который вы должны вызвать при обновлении значения внутри компонента, чтобы уведомить ngModel / formControl.Я предположил, что вы должны добавить в установленное значение:

 set value(time: Time | null) {
    console.log('Setting value to: ', time);
    time = time || new Time('', '');
    const newValue = {hour: time.hour, minute: time.minute};
    this.parts.setValue(newValue );
    this._onChange(newValue); // call the callback :)
    this.stateChanges.next();
  }

Для получения дополнительной информации здесь вы можете найти реализацию по умолчанию controlValueAccessor.Вы можете расширить этот класс в каждом компоненте, работающем с ngModel, и просто изменить значение ( this.value = 'newValue' ), а также переопределить writeValue, так как обычно требуется переход на ноги, необходимые для вашего компонента.https://github.com/xrobert35/asi-ngtools/blob/master/src/components/common/default-control-value-accessor.ts

...