【问题标题】:Angular2: Custom Select Component and Reactive FormsAngular2:自定义选择组件和反应形式
【发布时间】:2019-04-01 03:23:57
【问题描述】:

我在使用响应式表单和创建自定义选择组件时遇到了麻烦。

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

我查看了有关 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”?

任何不涉及太多手帕的琐碎解决方案?对于这样一件微不足道的事情,其余的解决方案似乎太复杂了。

编辑:我这样做的原因是因为这个“客户选择”将在应用程序的很多地方使用。

另外,我将不得不为其他 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>

【问题讨论】:

    标签: angular typescript angular5 angular2-forms


    【解决方案1】:

    我们在实现 ControlValueAccessors 的 Reactive Form Control 中为 Bootstrap 4 创建了一个自定义选择组件。这是代码,根据你的需要修改。

    组件:

    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>
    

    【讨论】:

      猜你喜欢
      • 2020-04-22
      • 2017-08-22
      • 2017-08-21
      • 2018-06-01
      • 2017-08-20
      • 2019-01-24
      • 2017-12-22
      • 2017-11-13
      • 1970-01-01
      相关资源
      最近更新 更多