Angular2:自定义选择组件和反应式表单 [英] Angular2: Custom Select Component and Reactive Forms
问题描述
我在使用 Reactive Forms 和创建自定义选择组件时遇到了麻烦.
我需要创建一些自定义选择组件.
我在 Stackoverflow 上查看了多个答案,其中涉及提供ControlValueAccessor"的实现.那些看起来可以工作,但对于我需要的东西来说非常重量级.
我也尝试过扩展SelectControlValueAccessor",但这似乎不是一件很常见的事情.如果它不常见,我会质疑这是否是解决我的问题的正确方法.
基本上,我需要一个自定义选择组件,它可以自动进行服务调用并使用响应式表单.
这与我想要做的类似:
@Component({选择器:'客户选择',styleUrls: ['./customer-select.component.css'],templateUrl: './customer-select.component.html'})导出类 CustomerSelectComponent 扩展 SelectControlValueAccess 实现 OnInit {客户:ICustomer[];构造函数(私人渲染:Renderer2,私有元素引用:元素引用,私人客户服务:客户服务,){超级(渲染,元素引用);}ngOnInit(): 无效 {this.customerService.getCustomers().subscribe((响应:IApiResponse) => {this.customers = response.Data;this.customers.sort(this.getFuncToSortMostUsedToDefaultOrdering());//额外的逻辑在这里},(错误:任何)=>控制台日志(错误),() =>console.log('getCustomers() 检索到的工作流'));}private getCompareToStrings(firstEl: string, secondEl: string) {如果 (firstEl < secondEl) {返回-1;}如果 (firstEl > secondEl) {返回 1;}返回0;}私人 getFuncToSortMostUsedToDefaultOrdering() {//假设我们有两个客户.return (firstElement: ICustomer, secondElement: ICustomer) =>{返回 SomeLogicHere.Compare(firstElement, secondElement)}}
这是 HTML 代码:
<select id="customer" class="form-control" formControlName="customer"><option *ngFor="让客户的客户" [ngValue]="客户">{{customer.CustomerNumber}}</选项></选择>
不要犹豫,提及我可能遗漏的任何细节.或者也许是我忽略的问题或设计讨论.
也许我可以使用组合而不是继承并组合SelectControlValueAccess",同时仍然实现ControlValueAccessor"?
任何不涉及太多手帕的琐碎解决方案?看起来其余的解决方案对于这样一件微不足道的事情来说是如此复杂.
我这样做的原因是因为这个客户选择"将在应用程序的很多地方使用.
此外,我将不得不为其他 5 个选择执行此操作,这就是为什么我不喜欢为如此琐碎的事情编写这么多代码的原因.
如果有人对此代码有任何输入,我认为此代码有效,也许是我忽略了一些内容,然后请分享:NEVERMIND BROKEN
@Component({选择器:'客户选择',templateUrl: './customer-select.component.html',供应商: [{提供:NG_VALUE_ACCESSOR,useExisting: forwardRef(() => CustomerSelectComponent),多:真}]})导出类 CustomerSelectComponent 扩展 SelectControlValueAccessor 实现 OnInit {客户:ICustomer[];构造函数(私人渲染:Renderer2,私有元素引用:元素引用,私有数据服务:数据服务,私人 fb:FormBuilder){超级(渲染,元素引用);}ngOnInit(): 无效 {this.dataService.getCustomers().subscribe((响应:IApiResponse) => {this.customers = response.Data;//附加逻辑},(错误:任何)=>控制台日志(错误),() =>console.log('getCustomers() 检索到的工作流'));}}
HTML:
我们在实现 ControlValueAccessors 的 Reactive Form Control 中为 Bootstrap 4 创建了一个自定义选择组件.这是代码,根据你的需要修改.
组件:
import {成分,初始化,输入,输出,事件发射器,简单的变化,转发参考,元素参考,视图子,OnChanges来自'@angular/core';从@angular/forms"导入 { ControlValueAccessor, NG_VALUE_ACCESSOR };@成分({选择器:'输入自定义选择控件',templateUrl: '...',styleUrls: ['......'],供应商: [{提供:NG_VALUE_ACCESSOR,多:真实,useExisting: forwardRef(() => SelectFormControlComponent)}]})导出类 SelectCustomFormControlComponent 实现 OnInit、ControlValueAccessor {@Output() dropdownEventUpdate: EventEmitter= new EventEmitter();公共 selectedDropDownValue = '';@Input() dropDownListArray: Array;构造函数(){}ngOnInit() {}写值(值:任何){如果(值){const matchObj = _.find(this.dropDownListArray, function(o) {返回 o.text === 值;});this.selectedDropDownValue = matchObj &&matchObj.text ?matchObj.text : '';}别的 {this.selectedDropDownValue = '选择';}}传播变化(时间:任何){控制台日志(时间);}registerOnChange(fn) {this.propagateChange = fn;}registerOnTouched() {}//tslint:disable-next-line:use-life-cycle-interfacengOnChanges(更改:SimpleChanges){}onDropDownChange = 函数(id,值){this.selectedDropDownValue = 值;this.dropdownEventUpdate.emit({身份证:身份证,文本:值});};}
模板:
<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>
调用模板代码:
<input-customselectcontrol (dropdownEventUpdate)="updateTopicDropdownEvent($event, i)" [dropDownListArray]="TopicsArray" name="selectdropdownvalue" formControlName="selectdropdownvalue"></input-customselectcontrol>
I am running into trouble with Reactive Forms and creating a custom select component.
I need to create some custom select component.
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.
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.
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)
}
}
Here's the HTML Code:
<!-- 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.
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.
EDIT: The reason I'm doing this is because this 'customer-select' will be used in so many places in the application.
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.
EDIT:
I think this code is working if anyone has any input on this code, perhaps something I overlooked, then please share: 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')
);
}
}
The HTML:
<select id="customer" class="form-control">
<option *ngFor="let customer of customers" [ngValue]="customer">
{{customer.CustomerNumber}}
</option>
</select>
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.
Component:
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
});
};
}
Template:
<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>
Calling Template Code:
<input-customselectcontrol (dropdownEventUpdate)="updateTopicDropdownEvent($event, i)" [dropDownListArray]="TopicsArray" name="selectdropdownvalue" formControlName="selectdropdownvalue"></input-customselectcontrol>
这篇关于Angular2:自定义选择组件和反应式表单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!