Angular2:自定义选择组件和反应形式 [英] Angular2: Custom Select Component and Reactive Forms

查看:64
本文介绍了Angular2:自定义选择组件和反应形式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用Reactive Forms并创建自定义选择组件时遇到麻烦.

I am running into trouble with Reactive Forms and creating a custom select component.

我需要创建一些自定义选择组件.

I need to create some custom select component.

我已经查看了关于Stackoverflow的多个答案,其中涉及提供"ControlValueAccessor"的实现.这些看起来像他们会工作,但对于我需要的东西却非常重要.

I've looked at multiple answers on Stackoverflow which involve providing an implementation of "ControlValueAccessor". Those look like they'd work but are very heavyweight for what I need.

我也一直在尝试扩展"SelectControlValueAccessor",但这似乎不是很平常的事情.如果不常见,我会问这是否是解决问题的正确方法.

I've also played around with extending "SelectControlValueAccessor" but it seems as though that isn't a very common thing. If it isn't common, I question whether it is the correct way to approach my problem.

基本上,我需要一个自定义的select组件,该组件会自动进行服务调用并使用反应式表单.

Basically, I need a custom select component which automatically makes a service call and works with reactive forms.

这与我要执行的操作类似:

This is similar to what I'm looking to do:

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

请毫不犹豫地提及我可能会遗漏的任何细节.也许是我忽略的问题或设计讨论.

Don't hesitate to mention any details that I might be missing. Or maybe questions or design discussions that I've overlooked.

也许我可以在继承上使用合成,并在仍然实现"ControlValueAccessor"的同时编写"SelectControlValueAccess"?

Perhaps I could use composition over inheritance and compose the 'SelectControlValueAccess' while still implementing 'ControlValueAccessor'?

任何不涉及太多麻烦的琐碎解决方案的小问题?看起来对于此类琐碎的事情,其余解决方案是如此复杂.

Any trivial solutions that don't involve too much hanky panky? It just seems like the rest of the solutions are so complicated for such a trivial thing.

之所以这样做,是因为此客户选择"将在应用程序中的很多地方使用.

The reason I'm doing this is because this 'customer-select' will be used in so many places in the application.

此外,我将不得不为其他5个选择执行此操作,这就是为什么我不喜欢那么多琐碎的代码的原因.

Also, I will have to do this for like 5 other selects which is why I don't like so much code for something so trivial.

我认为,如果有人对此代码有任何输入(也许我忽略了某些内容),那么此代码就可以正常工作,请分享:永远不要破碎

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

推荐答案

我们在Reactive Form Control中为Bootstrap 4创建了一个自定义的select组件,该组件实现了ControlValueAccessors.这是代码,请根据您的需要进行修改.

We created a custom select component for Bootstrap 4 in Reactive Form Control which implements ControlValueAccessors. Here is the code, modify based on ur needs.

组件:

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>

这篇关于Angular2:自定义选择组件和反应形式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆