Angular MatFormControl, ControlValueAccessor - PullRequest
0 голосов
/ 17 апреля 2020

У меня есть пользовательский компонент, это упаковка для выбора матов. Как я могу использовать его в других компонентах? Я читал о formControl и controlValueAccessor, но я много не понимаю.

мой заказ. html

    <mat-select>
<mat-option [value]="opt" *ngFor="let op of opt; index as i">{{opt[i]}}</mat-option>
</mat-select>
<input matInput>

мой custom.ts

import { Component, OnInit, Input } from '@angular/core';
import { MatFormFieldControl } from '@angular/material/form-field';

@Component({
  selector: 'cust-input',
  templateUrl: './input.component.html',
  styleUrls: ['./input.component.scss'],
  providers: [{provide: MatFormFieldControl, useExisting: InputComponent}]

})
export class InputComponent extends MatFormFieldControl<string> implements OnInit {

  @Input() opt: string;

  setDescribedByIds(ids: string[]): void {
    throw new Error('Method not implemented.');
  }
  onContainerClick(event: MouseEvent): void {
    throw new Error('Method not implemented.');
  }

  constructor() {
    super();
  }

  ngOnInit(): void {
  }

}

мое приложение. html

<mat-form-field>
  <cust-input [opt]="myopt"></cust-input>
</mat-form-field>

мое приложение.ts

import { Component } from '@angular/core';




@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'form';
  myopt = ['a', 'b', 'c', 'd'];



}

Мне не нужно что-то вроде моего custmo. html

  <mat-form-field>
     <mat-select>
    <mat-option [value]="opt" *ngFor="let op of opt; index as i">{{opt[i]}}</mat-option>
    </mat-select>
    <input matInput>
    </mat-form-field>

stackbiz

1 Ответ

0 голосов
/ 25 апреля 2020

поэтому ответ таков: если мы хотим использовать нашу пользовательскую обертку, нам нужно создать для нее настраиваемый элемент управления полем формы, в нашем случае нам нужно создать собственный элемент управления mat-form-field-control

// наш пользовательский элемент управления полем формы

import { ValueAccessor } from './value-accessor';
import { MatFormFieldControl } from '@angular/material/form-field';
import {
  Input,
  HostBinding,
  Optional,
  Self,
  ElementRef,
  OnDestroy,
  Directive,
} from '@angular/core';
import { FocusMonitor } from '@angular/cdk/a11y';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { NgControl } from '@angular/forms';
import { Subject } from 'rxjs';

@Directive()
export class FormControlDirective<T> extends ValueAccessor<T>
  implements MatFormFieldControl<T>, OnDestroy {
  @Input()
  get value() {
    return this._value;
  }
  set value(val: T) {
    if (val !== this._value) {
      this._value = val;
      this.stateChanges.next();
    }
  }

  @Input()
  get placeholder() {
    return this._placeholder;
  }
  set placeholder(plc: string) {
    this._placeholder = plc;
    this.stateChanges.next();
  }

  @Input()
  get required() {
    return this._required;
  }
  set required(req: boolean) {
    this._required = coerceBooleanProperty(req);
    this.stateChanges.next();
  }

  get empty() {
    return !this._value;
  }

  constructor(
    @Optional() @Self() public ngControl: NgControl,
    private fM: FocusMonitor,
    private elRef: ElementRef<HTMLElement>
  ) {
    super();

    if (this.ngControl != null) {
      this.ngControl.valueAccessor = this;
    }

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

  @HostBinding('class.floating')
  get shouldLabelFloat() {
    return this.focused || !this.empty;
  }

  private _value: T | null;
  private _placeholder: string;
  private _required = false;
  nextId = 0;
  stateChanges: Subject<void> = new Subject<void>();
  focused = false;

  @HostBinding() id = `${this.nextId++}`;

  errorState = false;
  controlType = 'my-select';
  autofilled?: boolean;

  @HostBinding('attr.aria-desribedby') describedBy = '';

  setDescribedByIds(ids: string[]): void {
    this.describedBy = ids.join('');
  }
  onContainerClick(event: MouseEvent): void {
    if ((event.target as Element).tagName.toLowerCase() === 'input') {
      this.elRef.nativeElement.focus();
    }
  }

  ngOnDestroy(): void {
    this.fM.stopMonitoring(this.elRef.nativeElement);
    this.stateChanges.complete();
  }
}

Но, если мы хотим использовать ngModel в нашей оболочке, нам также необходимо создать наш метод доступа к пользовательскому значению элемента управления

custo value accesor

import { ControlValueAccessor } from '@angular/forms';

export class ValueAccessor<T> implements ControlValueAccessor {
  value: T | null;
  onChange: Function;
  onTouched: Function;
  disabled: boolean;

  writeValue(val: T): void {
    this.value = val;
  }
  registerOnChange(fn: Function): void {
    this.onChange = fn;
  }
  registerOnTouched(fn: Function): void {
    this.onTouched = fn;
  }
  setDisabledState?(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }
}

В нашем custom.wrapper.component.ts нам нужно расширить наш контроль формы, а также посмотреть в custom-form-field-control и посмотреть на consructor, есть ngControl, мы добавляем его туда для одновременного использования контроля формы и средства доступа к значениям.

select.component.ts

import { Component, Input, OnInit } from '@angular/core';
import { MatFormFieldControl } from '@angular/material/form-field';
import { FormControlDirective } from 'src/app/forms/form-control';

@Component({
  selector: 'app-select',
  templateUrl: './select.component.html',
  styleUrls: ['./select.component.scss'],
  providers: [{ provide: MatFormFieldControl, useExisting: SelectComponent }],
})
export class SelectComponent extends FormControlDirective<string>
  implements OnInit {
  @Input() option: string;

  ngOnInit() {}
}

в файле wrapper.component.ts. там мы говорим Native MatFormFieldControl, что-то вроде (Привет, у меня есть свой собственный контроль формы, давайте использовать его). Следующим шагом является создание нашего wrapp

select.component. html

<mat-select [(ngModel)]="value">
  <mat-option [value]="item" *ngFor="let item of option; index as j">{{
    option[j]
  }}</mat-option>
</mat-select>

Итак, пока мы можем использовать его в других сопонентах, внутри mat-form-field

app.component. html

<mat-form-field>
  <mat-label>label</mat-label>
  <app-select [option]="opt" [(ngModel)]="title"></app-select>
</mat-form-field>

есть несколько полезных ссылок:

официальная документация

старая, но очень полезный пост

А сейчас у меня другая проблема XD Как мне нужно использовать ngModel, точно в, но это в app-select & mat-select одновременно. Когда я нахожу ответ, я редактирую это

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