Angular2: пользовательский выбор компонентов и реактивные формы - PullRequest
0 голосов
/ 27 октября 2018

У меня проблемы с Reactive Forms и созданием пользовательского компонента выбора.

Мне нужно создать некоторый пользовательский компонент выбора.

Я рассмотрел несколько ответов по Stackoverflow, которые включают в себя реализацию реализации ControlValueAccessor.Они выглядят так, как будто они работают, но они очень тяжелы для того, что мне нужно.

Я также поиграл с расширением «SelectControlValueAccessor», но кажется, что это не очень распространенная вещь.Если это не распространено, я спрашиваю, является ли это правильным подходом к моей проблеме.

По сути, мне нужен пользовательский компонент выбора, который автоматически выполняет вызов службы и работает с реактивными формами.

Это похоже на то, что я собираюсь сделать:

@Component({
    selector: 'customer-select',
    styleUrls: ['./customer-select.component.css'],
    templateUrl: './customer-select.component.html'
})
export class CustomerSelectComponent extends SelectControlValueAccess implements OnInit {
    customers: ICustomer[];

    constructor(
        private render: Renderer2,
        private elementRef: ElementRef,
        private customerService: CustomerService,
    ) {
        super(render, elementRef);
    }

    ngOnInit(): void {
        this.customerService.getCustomers()
           .subscribe((response: IApiResponse<ICustomer[]>) => {
                    this.customers = response.Data;
                   this.customers.sort(this.getFuncToSortMostUsedToDefaultOrdering());

                   // additional logic goes here 
                },
               (err: any) => console.log(err),
                () => console.log('getCustomers() retrieved workflows')
           );
    }

    private getCompareToStrings(firstEl: string, secondEl: string) {
        if (firstEl < secondEl) {
            return -1;
        }
        if (firstEl > secondEl) {
            return 1;
        }
        return 0;
    }

    private getFuncToSortMostUsedToDefaultOrdering() {
        // Assuming that we have two customers.
        return (firstElement: ICustomer, secondElement: ICustomer) => {
            return SomeLogicHere.Compare(firstElement, secondElement)
    }

}

Вот код HTML:

<!-- Need the formControlName somehow passed in ---> 
<select id="customer" class="form-control" formControlName="customer">
    <option *ngFor="let customer of customers" [ngValue]="customer">
        {{customer.CustomerNumber}}
    </option>
</select>

Не стесняйтесь упоминать какие-либо подробности, которые я мог бы пропустить,Или, может быть, вопросы или обсуждения дизайна, которые я пропустил.

Может быть, я мог бы использовать композицию поверх наследования и создать «SelectControlValueAccess», продолжая при этом реализовывать «ControlValueAccessor»?

Какие-нибудь тривиальные решения, в которых не используется слишком много платок?Просто кажется, что остальные решения настолько сложны для такой тривиальной вещи.

РЕДАКТИРОВАТЬ: причина, по которой я это делаю, заключается в том, что этот 'customer-select' будет использоваться во многих местах приложения.

Кроме того, мне придется сделать это для5 других вариантов выбора, поэтому я не люблю так много кода для чего-то такого тривиального.

РЕДАКТИРОВАТЬ:

Я думаю, что этот код работает, если у кого-то есть какие-либо входы по этому коду, возможно, что-то я пропустил, то, пожалуйста, поделитесь: NEVERMIND BROKEN

@Component({
    selector: 'customer-select',
    templateUrl: './customer-select.component.html',
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => CustomerSelectComponent),
            multi: true
        }
    ]
})
export class CustomerSelectComponent extends SelectControlValueAccessor implements OnInit {
    customers: ICustomer[];

    constructor(
        private render: Renderer2, 
        private elementRef: ElementRef,
        private dataService: DataService,
        private fb: FormBuilder
    ) {
        super(render, elementRef);
    }

    ngOnInit(): void {
        this.dataService.getCustomers()
            .subscribe((response: IApiResponse<ICustomer[]>) => {
                    this.customers = response.Data;
                    // Additional Logic
                },
                (err: any) => console.log(err),
                () => console.log('getCustomers() retrieved workflows')
            );
    }
}

HTML:

<select id="customer" class="form-control">
    <option *ngFor="let customer of customers" [ngValue]="customer">
        {{customer.CustomerNumber}}
    </option>
</select>

1 Ответ

0 голосов
/ 27 октября 2018

Мы создали пользовательский компонент выбора для Bootstrap 4 в Reactive Form Control, который реализует ControlValueAccessors.Вот код, изменяемый в зависимости от ваших потребностей.

Компонент:

import {
  Component,
  OnInit,
  Input,
  Output,
  EventEmitter,
  SimpleChanges,
  forwardRef,
  ElementRef,
  ViewChild,
  OnChanges
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: 'input-customselectcontrol',
  templateUrl: '...',
  styleUrls: ['......'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      multi: true,
      useExisting: forwardRef(() => SelectFormControlComponent)
    }
  ]
})
export class SelectCustomFormControlComponent implements OnInit, ControlValueAccessor {
  @Output() dropdownEventUpdate: EventEmitter<any> = new EventEmitter();
  public selectedDropDownValue = '';
  @Input() dropDownListArray: Array<any>;

  constructor() {}

  ngOnInit() {}

  writeValue(value: any) {
    if (value) {
      const matchObj = _.find(this.dropDownListArray, function(o) {
          return o.text === value;
        });
        this.selectedDropDownValue = matchObj && matchObj.text ? matchObj.text : '';
      }else {
      this.selectedDropDownValue = 'Select';
    }
  }

  propagateChange(time: any) {
    console.log(time);
  }

  registerOnChange(fn) {
    this.propagateChange = fn;
  }

  registerOnTouched() {}

  // tslint:disable-next-line:use-life-cycle-interface
  ngOnChanges(changes: SimpleChanges) {

  }

  onDropDownChange = function(id, value) {
    this.selectedDropDownValue = value;
    this.dropdownEventUpdate.emit({
      id: id,
      text: value
    });
  };
}

Шаблон:

<div ngbDropdown class="d-inline-block custom-btn-color col-md px-0 w-100" #inputDropdown="ngbDropdown">
  <button class="btn btn-outline-primary custom-height px-2 dropdown-custom w-100 custom-drop-down-text-override pr-4 text-left" [ngClass]="{'input-errorCls': isRequiredError}" id="sortMenu" ngbDropdownToggle>{{selectedDropDownValue}}</button>
  <div ngbDropdownMenu aria-labelledby=" sortMenu" class="w-100">
    <button class="dropdown-item px-3 custom-drop-down-text-override" *ngFor="let value of dropDownListArray" (click)="onDropDownChange(value.id, value.text);$event.stopPropagation();">{{value.text}}</button>
  </div>
</div>

Код вызывающего шаблона:

<input-customselectcontrol (dropdownEventUpdate)="updateTopicDropdownEvent($event, i)" [dropDownListArray]="TopicsArray"  name="selectdropdownvalue" formControlName="selectdropdownvalue"></input-customselectcontrol>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...