AppComponent FormControl, кажется, не связывается с пользовательским вводом материала FormControl - PullRequest
1 голос
/ 06 февраля 2020

Я работаю над пользовательским компонентом материала, но во время тестирования входное значение не отправляется родительскому компоненту. Значение элемента управления формы в AppComponent всегда равно нулю.

app.component.ts

import { Component, ChangeDetectionStrategy } from '@angular/core';
import { FormControl } from '@angular/forms';

@Component({
  selector: 'ipmon-cartoppo-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {
  title = 'test-carte';

  numCarteCtrl = new FormControl();

}

app.component. html

<h1>Welcome to test-cartes!</h1>
<label>Carte</label>
<cartoppy-saisie-numero-carte formControl="numCarteCtrl" required="false" placeholder="____ ____ ____ ____"></cartoppy-saisie-numero-carte>

<span
  >Valeur dans l'app :

  {{ numCarteCtrl.value | json }}
</span>

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { CartoppyLibCarteModule } from '@ipmon-cartoppo/cartoppy-lib-carte';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, BrowserAnimationsModule, CartoppyLibCarteModule, ReactiveFormsModule],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

sais ie -numero-carte.component. html

<code><mat-form-field>
  <input
    matInput
    cartoppyNumCarte
    type="text"
    [formControl]="numeroCarteCtrl"
    [id]="labelforId"
    [placeholder]="placeholder"
    [required]="required"
    maxlength="19"
  />
  <mat-error *ngIf="numeroCarteCtrl.hasError('required')">
    La saisie de ce champ est obligatoire.
  </mat-error>
</mat-form-field>
<span
  >Valeur du champs :
  <pre>
    {{ numeroCarteCtrl.value }}
    {{ required }}
  

sais ie -numero-carte.component.ts

import { Component, OnInit, ElementRef, Input, OnDestroy, ChangeDetectionStrategy, HostBinding, Optional, Self } from '@angular/core';
import { FormControl, NgControl, ControlValueAccessor} from '@angular/forms';
import { tap, distinctUntilChanged, takeUntil } from 'rxjs/operators';
import { MatFormFieldControl } from '@angular/material';
import { Subject } from 'rxjs';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { FocusMonitor } from '@angular/cdk/a11y';
/**
 * Composant pour saisir numéro carte
 */
@Component({
  selector: 'cartoppy-saisie-numero-carte',
  templateUrl: './saisie-numero-carte.component.html',
  styleUrls: ['./saisie-numero-carte.component.scss'],
  providers: [
    {
      provide: MatFormFieldControl,
      useExisting: SaisieNumeroCarteComponent
    }
  ],
  changeDetection: ChangeDetectionStrategy.OnPush
})

/**
 * Class Composant
 */
export class SaisieNumeroCarteComponent implements OnInit, ControlValueAccessor, MatFormFieldControl<string>, OnDestroy {
  static nextISaisieNumCarteComponent = 0;

  /**
   * Lié à l'attribut labelfor du label, il permet de donner le focus au champ
   */
  @Input()
  labelforId: string;

  /**
   * id du control
   */
  @HostBinding()
  id = `saisie-num-carte-${SaisieNumeroCarteComponent.nextISaisieNumCarteComponent++}`;

  /**
   * Form control du numéro carte
   */
  numeroCarteCtrl = new FormControl();

  stateChanges = new Subject<void>();

  describedBy = '';

  focused: boolean;

  shouldLabelFloat: boolean;

  private destroy$ = new Subject<void>();

  private _value = '';

  private _placeholder: string;

  private _required = false;

  private _readOnly = false;

  private _disabled = false;

  onChange = (_: any) => {};

  onTouched = () => {};

  get empty(): boolean {
    return !this.value;
  }

  /**
   * param disabled du control
   */
  @Input()
  get disabled(): boolean {
    return this._disabled;
  }
  set disabled(value: boolean) {
    this._disabled = coerceBooleanProperty(value);
    this._disabled ? this.numeroCarteCtrl.disable() : this.numeroCarteCtrl.enable();
    this.stateChanges.next();
  }

  /**
   * param placeholder du control
   */
  @Input()
  get placeholder(): string {
    return this._placeholder;
  }
  set placeholder(value: string) {
    this._placeholder = value;
    this.stateChanges.next();
  }

  /**
   * param required du control
   */
  @Input()
  get required(): boolean {
    return this._required;
  }
  set required(value: boolean) {
    this._required = coerceBooleanProperty(value);
    this.stateChanges.next();
  }

  /**
   * param readOnly du control
   */
  @Input()
  get readOnly(): boolean {
    return this._readOnly;
  }
  set readOnly(value: boolean) {
    this._readOnly = coerceBooleanProperty(value);
  }

  /**
   * param value du control
   */
  @Input()
  get value(): string | null {
    return this._value;
  }
  set value(numCarte: string | null) {
    console.log('numCarte: ', numCarte);
    if (numCarte) {
      this.numeroCarteCtrl.setValue(numCarte.replace(/\s+/g, ''));
      this.onChange(numCarte);
      this.stateChanges.next();
    }
  }

  get errorState() {
    return this.ngControl.errors !== null && !!this.ngControl.touched;
  }

  /**
   * constructor
   * @param _elementRef ElementRef<HTMLElement>
   */
  constructor(@Optional() @Self() public ngControl: NgControl, private fm: FocusMonitor, private _elementRef: ElementRef<HTMLElement>) {
    if (this.ngControl != null) {
      this.ngControl.valueAccessor = this;
    }
    fm.monitor(_elementRef.nativeElement, true).subscribe(origin => {
      this.focused = !!origin;
      if (!this.focused && typeof this.numeroCarteCtrl.value === 'string') {
        this.numeroCarteCtrl.setValue(undefined);
      }
      this.stateChanges.next();
    });
  }

  /**
   * Fonction appelée quand le composant est initié
   */
  ngOnInit() {
    this.numeroCarteCtrl.valueChanges
      .pipe(
        takeUntil(this.destroy$),
        distinctUntilChanged(),
        tap((numero: string) => {
          console.log('numero: ', numero);
          this.value = numero;
        })
      )
      .subscribe();
  }

  /**
   * Fonction de l'inteface ControlValueAccessor
   */
  writeValue(obj: string | null): void {
    console.log('----- In writeValue -----: ', obj);
    this.value = obj;
  }

  /**
   * Fonction de l'inteface ControlValueAccessor
   */
  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  /**
   * Fonction de l'inteface ControlValueAccessor
   */
  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  /**
   * Fonction de l'inteface ControlValueAccessor
   */
  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  /**
   * Fonction du class MatFormFieldControl
   * @param ids  tableau
   */
  setDescribedByIds(ids: string[]): void {
    this.describedBy = ids.join(' ');
  }

  /**
   *  Fonction du class MatFormFieldControl
   * @param event MouseEvent
   */
  onContainerClick(event: MouseEvent): void {
    if ((event.target as Element).tagName.toLowerCase() !== 'input') {
      const input: HTMLInputElement | null = this._elementRef.nativeElement.querySelector('input');
      if (input) {
        input.focus();
      }
    }
  }

  /**
   * Fonction appelée avant la destruction du component
   */
  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
    this.stateChanges.complete();
    this.fm.stopMonitoring(this._elementRef.nativeElement);
  }
}

cartoppy-lib -carte.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SaisieNumeroCarteComponent } from './components/saisie-numero-carte/saisie-numero-carte.component';
import { MatFormFieldModule, MatInputModule, MAT_LABEL_GLOBAL_OPTIONS } from '@angular/material';
import { ReactiveFormsModule } from '@angular/forms';
import { NumCarteDirective } from './directives/num-carte.directive';

/**
 * Module CartoppyLibCarteModule
 */
@NgModule({
  imports: [CommonModule, MatFormFieldModule, MatInputModule, ReactiveFormsModule],
  declarations: [SaisieNumeroCarteComponent, NumCarteDirective],
  exports: [SaisieNumeroCarteComponent],
  providers: [{ provide: MAT_LABEL_GLOBAL_OPTIONS, useValue: { float: 'never' } }]
})
export class CartoppyLibCarteModule {}

1 Ответ

1 голос
/ 06 февраля 2020

Я думаю, что передача значений изменения в родительский отсутствует

Изменить formControl="numCarteCtrl" на formControlName="numCarteCtrl"

добавить ниже в конструкторе

 this.numeroCarteCtrl.valueChanges.subscribe(val => {
   this.onChnage(val)
  });

Или использовать ниже

   ngOnChanges(inputs) {
        this.onChange(this.numeroCarteCtrl.value);
    }

Здесь работает stackblitz .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...