Angular 6 Reactive Forms - 根据条件动态设置 <select> FormControl 的选定 <option>
Angular 6 Reactive Forms - Set the selected <option> of a <select> FormControl dynamically by condition
我需要知道如何根据条件动态设置 <select>
FormControl 的 selected <option>
。
假设我们有客户下单。有一个下拉菜单,我们 select 一个客户,根据该客户,订单下拉菜单的选项应动态设置,特定订单应 selected。
此外,两个下拉菜单都有一个 <option>
“(new customer/order)”,以防还没有客户或订单,所以如果我们在没有客户的情况下转到该表单,这个“新”选项应该在两个下拉菜单中 selected。如果我们有一个没有订单的客户,“新”选项应该在订单下拉菜单中 selected。
这是form.component.html:
<form [formGroup]="customerForm">
<select formControlName="customers">
<option>(new customer)</option>
<option [ngValue]="customer" *ngFor="let customer of customers">
{{customer.name}}
</option>
</select>
<select formControlName="orders">
<option>(new order)</option>
<option [ngValue]="order" *ngFor="let order of filteredOrders">
{{order.id}}
</option>
</select>
</form>
这是form.component.ts:
customerForm: FormGroup;
customers: Customer[] = [
{ "id": 1,
"name": "Meghan Castellano",
"orderIds": [1,2] },
{ "id": 2,
"name": "Monika Weiss",
"orderIds": [3,4] }];
orders: Order[] = [{"id": 1},{"id": 2},{"id": 3},{"id": 4}];
filteredOrders: Order[];
constructor( private route: ActivatedRoute,
private fb: FormBuilder) {}
ngOnInit() {
this.customerForm = this.fb.group({
customers: '',
orders: '' });
let customerId = this.route.snapshot.getParam('id');
if (customerId == 0) {
this.customerForm.patchValue({
customers: "(new customer)",
orders: "(new order)" });
}
else
{
let customer = this.customers[customerId];
this.customerForm.patchValue({ customers: customer.name });
if (customer.orderIds.length != 0) {
this.filteredOrders = getCustomersOrders(customer);
this.customerForm.patchValue({
orders: this.filteredOrders[0].id }
}
}
}
getCustomersOrders(customer: Customer): Order[] {
let orders: Order[];
for (var id = 0; id < customer.orderIds.length; id++) {
let orderId = customer.orderIds[id];
let order = this.orders.find(i => i.id == orderId);
orders.push(order); }
return orders;
}
目前我正在路由到表单并提供带有 url 的 ID。客户下拉菜单 select 是正确的客户,具体取决于 url.
中的 ID
但是,订单下拉菜单只填充正确,但 selection 不起作用。 selected 根本没有选项。
如果我替换这条语句中的值:
this.customerForm.patchValue({ orders: this.filteredOrders[0].id }
与 "(new order)"
字符串已在 html 中指定:
this.customerForm.patchValue({ order: "(new order)" })
有效。字符串 "(new order)"
在订单下拉菜单中被 select 编辑。它只是不适用于 filteredOrders。
我在这里做错了什么?我可能需要一种完全不同的方法吗?
我认为问题出在订单选择器中选择的对象(实际上也在客户选择器中)。
<option [ngValue]="order" *ngFor="let order of filteredOrders">
{{order.id}}
</option>
这意味着将选择整个 order
对象,而不仅仅是订单 ID。在这种情况下,如果您尝试仅使用 order.id
修补该值,那么它将不起作用:选择器等待 Order
对象,而不是 order.id
。
我将一个快速的 stackblitz 与您在问题中输入的代码的工作版本放在一起:https://stackblitz.com/edit/angular-drop-dowb。唯一真正的区别是
this.customerForm.patchValue({
orders: this.filteredOrders[0]
});
使用 代替
this.customerForm.patchValue({
orders: this.filteredOrders[0].id }
});
更新
所以,我更新了 stackblitz。
要使 orders
字段沿 customer
保持正确的值,您需要在 select
字段中添加 (change)
。
<select formControlName="customers" (change)="updateOrders($event)">
<option [ngValue]="null">(new customer)</option>
<option [value]="customer.id" *ngFor="let customer of customers" >
{{customer.name}}
</option>
</select>
不要忘记传递客户 id
字段作为值而不是 customer
- Angular 似乎不喜欢它。使用 id
值,您需要在 component.ts
.
中添加一个 updateOrders
函数
updateOrders(event) {
const index = this.customers.findIndex(item => item.id == event.target.value);
if (index === -1) {
this.customerForm.controls.orders.setValue(null);
return;
}
this.filteredOrders = this.getCustomersOrders(this.customers[index]);
this.customerForm.controls.orders.setValue(this.filteredOrders[0]);
}
如果 id
不在客户列表中,那么您只需使用 null
值更新 orders
,对应于您的 (new order)
.如果 id
在客户列表中,那么您将更新 filteredOrders
。
好的,几个小时后我明白了。这是我更新的 .html 和 .ts 文件,供您参考:
HTML:
<form class="form-container" [formGroup]="customerForm">
<select formControlName="customer" (change)="onCustomerChanged($event)">
<option>(new customer)</option>
<option *ngFor="let customer of customers" [value]="customer.name">
{{customer.name}}
</option>
</select>
<select formControlName="order">
<option>(new order)</option>
<option *ngFor="let order of filteredOrders" [value]="order.id">
{{order.id}}</option>
</select>
</form>
.ts-文件
export class CustomerFormComponent implements OnInit {
customerForm: FormGroup;
selectedCustomer: Customer;
filteredOrders: Order[];
customers: Customer[] = [...];
orders: Order[] = [...];
constructor(private route: ActivatedRoute,
private fb: FormBuilder) { }
ngOnInit() {
this.customerForm = this.fb.group({
customer: "",
order: ""
});
let customerId = Number(this.route.snapshot.paramMap.get('customerId'));
this.setFormControlValues(customerId);
}
setFormControlValues(customerId: number) {
if (customerId == 0) {
this.customerForm.get('customer').setValue("(new customer)");
this.customerForm.get('order').setValue("(new order)");
}
else {
this.selectedCustomer = this.customers.find(i => i.id == customerId);
this.filteredOrders = this.getCustomerOrders(this.selectedCustomer);
this.customerForm.get('customer').setValue(this.selectedCustomer.name);
this.customerForm.get('order').setValue(this.filteredOrders[0].orderNumber);
}
}
getCustomerOrders(customer: Customer) : Order[] {
let orders: Order[] = [];
for (var id = 0; id < customer.orderIds.length; id++) {
let orderId = customer.orderIds[id];
orders.push(this.orders.find(i => i.id == orderId));
}
return orders;
}
onCustomerChanged(event: any) {
this.selectedCustomer = this.customers.find(n => n.name == event.target.value);
this.setFormControlValues(this.selectedCustomer.id);
}
}
如您所见,在 HTML 中,我现在使用“[value]”代替“[ngValue]”,使用“customer.name”/“order.id”代替只有“客户”/“订单”。
在 .ts 文件中,我去掉了“patchValue()”方法并引入了“setValue”方法。
这是有效的 stackblitz 示例:
https://stackblitz.com/edit/angular-conditionaldropdown-gnajge
如果您使用的是 [ngValue]
,则可以在 select
元素上使用 [compareWith]
,通过比较函数来确定是否选择了该值。使用 [ngValue]
允许复杂对象超过 [value]
,这是一个字符串。
<form [formGroup]="customerForm">
<select [compareWith]="compareCustomers" formControlName="customers">
<option>(new customer)</option>
<option [ngValue]="customer" *ngFor="let customer of customers">
{{customer.name}}
</option>
</select>
<select [compareWith]="compareOrders" formControlName="orders">
<option>(new order)</option>
<option [ngValue]="order" *ngFor="let order of filteredOrders">
{{order.id}}
</option>
</select>
</form>
export class SomeComponent {
public compareCustomer(a: Customer, b: Customer): boolean {
return a.id === b.id;
}
public compareOrders(a: Order, b: Order): boolean {
return a.id === b.id;
}
}
我需要知道如何根据条件动态设置 <select>
FormControl 的 selected <option>
。
假设我们有客户下单。有一个下拉菜单,我们 select 一个客户,根据该客户,订单下拉菜单的选项应动态设置,特定订单应 selected。
此外,两个下拉菜单都有一个 <option>
“(new customer/order)”,以防还没有客户或订单,所以如果我们在没有客户的情况下转到该表单,这个“新”选项应该在两个下拉菜单中 selected。如果我们有一个没有订单的客户,“新”选项应该在订单下拉菜单中 selected。
这是form.component.html:
<form [formGroup]="customerForm">
<select formControlName="customers">
<option>(new customer)</option>
<option [ngValue]="customer" *ngFor="let customer of customers">
{{customer.name}}
</option>
</select>
<select formControlName="orders">
<option>(new order)</option>
<option [ngValue]="order" *ngFor="let order of filteredOrders">
{{order.id}}
</option>
</select>
</form>
这是form.component.ts:
customerForm: FormGroup;
customers: Customer[] = [
{ "id": 1,
"name": "Meghan Castellano",
"orderIds": [1,2] },
{ "id": 2,
"name": "Monika Weiss",
"orderIds": [3,4] }];
orders: Order[] = [{"id": 1},{"id": 2},{"id": 3},{"id": 4}];
filteredOrders: Order[];
constructor( private route: ActivatedRoute,
private fb: FormBuilder) {}
ngOnInit() {
this.customerForm = this.fb.group({
customers: '',
orders: '' });
let customerId = this.route.snapshot.getParam('id');
if (customerId == 0) {
this.customerForm.patchValue({
customers: "(new customer)",
orders: "(new order)" });
}
else
{
let customer = this.customers[customerId];
this.customerForm.patchValue({ customers: customer.name });
if (customer.orderIds.length != 0) {
this.filteredOrders = getCustomersOrders(customer);
this.customerForm.patchValue({
orders: this.filteredOrders[0].id }
}
}
}
getCustomersOrders(customer: Customer): Order[] {
let orders: Order[];
for (var id = 0; id < customer.orderIds.length; id++) {
let orderId = customer.orderIds[id];
let order = this.orders.find(i => i.id == orderId);
orders.push(order); }
return orders;
}
目前我正在路由到表单并提供带有 url 的 ID。客户下拉菜单 select 是正确的客户,具体取决于 url.
中的 ID但是,订单下拉菜单只填充正确,但 selection 不起作用。 selected 根本没有选项。
如果我替换这条语句中的值:
this.customerForm.patchValue({ orders: this.filteredOrders[0].id }
与 "(new order)"
字符串已在 html 中指定:
this.customerForm.patchValue({ order: "(new order)" })
有效。字符串 "(new order)"
在订单下拉菜单中被 select 编辑。它只是不适用于 filteredOrders。
我在这里做错了什么?我可能需要一种完全不同的方法吗?
我认为问题出在订单选择器中选择的对象(实际上也在客户选择器中)。
<option [ngValue]="order" *ngFor="let order of filteredOrders">
{{order.id}}
</option>
这意味着将选择整个 order
对象,而不仅仅是订单 ID。在这种情况下,如果您尝试仅使用 order.id
修补该值,那么它将不起作用:选择器等待 Order
对象,而不是 order.id
。
我将一个快速的 stackblitz 与您在问题中输入的代码的工作版本放在一起:https://stackblitz.com/edit/angular-drop-dowb。唯一真正的区别是
this.customerForm.patchValue({
orders: this.filteredOrders[0]
});
使用 代替
this.customerForm.patchValue({
orders: this.filteredOrders[0].id }
});
更新
所以,我更新了 stackblitz。
要使 orders
字段沿 customer
保持正确的值,您需要在 select
字段中添加 (change)
。
<select formControlName="customers" (change)="updateOrders($event)">
<option [ngValue]="null">(new customer)</option>
<option [value]="customer.id" *ngFor="let customer of customers" >
{{customer.name}}
</option>
</select>
不要忘记传递客户 id
字段作为值而不是 customer
- Angular 似乎不喜欢它。使用 id
值,您需要在 component.ts
.
updateOrders
函数
updateOrders(event) {
const index = this.customers.findIndex(item => item.id == event.target.value);
if (index === -1) {
this.customerForm.controls.orders.setValue(null);
return;
}
this.filteredOrders = this.getCustomersOrders(this.customers[index]);
this.customerForm.controls.orders.setValue(this.filteredOrders[0]);
}
如果 id
不在客户列表中,那么您只需使用 null
值更新 orders
,对应于您的 (new order)
.如果 id
在客户列表中,那么您将更新 filteredOrders
。
好的,几个小时后我明白了。这是我更新的 .html 和 .ts 文件,供您参考:
HTML:
<form class="form-container" [formGroup]="customerForm">
<select formControlName="customer" (change)="onCustomerChanged($event)">
<option>(new customer)</option>
<option *ngFor="let customer of customers" [value]="customer.name">
{{customer.name}}
</option>
</select>
<select formControlName="order">
<option>(new order)</option>
<option *ngFor="let order of filteredOrders" [value]="order.id">
{{order.id}}</option>
</select>
</form>
.ts-文件
export class CustomerFormComponent implements OnInit {
customerForm: FormGroup;
selectedCustomer: Customer;
filteredOrders: Order[];
customers: Customer[] = [...];
orders: Order[] = [...];
constructor(private route: ActivatedRoute,
private fb: FormBuilder) { }
ngOnInit() {
this.customerForm = this.fb.group({
customer: "",
order: ""
});
let customerId = Number(this.route.snapshot.paramMap.get('customerId'));
this.setFormControlValues(customerId);
}
setFormControlValues(customerId: number) {
if (customerId == 0) {
this.customerForm.get('customer').setValue("(new customer)");
this.customerForm.get('order').setValue("(new order)");
}
else {
this.selectedCustomer = this.customers.find(i => i.id == customerId);
this.filteredOrders = this.getCustomerOrders(this.selectedCustomer);
this.customerForm.get('customer').setValue(this.selectedCustomer.name);
this.customerForm.get('order').setValue(this.filteredOrders[0].orderNumber);
}
}
getCustomerOrders(customer: Customer) : Order[] {
let orders: Order[] = [];
for (var id = 0; id < customer.orderIds.length; id++) {
let orderId = customer.orderIds[id];
orders.push(this.orders.find(i => i.id == orderId));
}
return orders;
}
onCustomerChanged(event: any) {
this.selectedCustomer = this.customers.find(n => n.name == event.target.value);
this.setFormControlValues(this.selectedCustomer.id);
}
}
如您所见,在 HTML 中,我现在使用“[value]”代替“[ngValue]”,使用“customer.name”/“order.id”代替只有“客户”/“订单”。
在 .ts 文件中,我去掉了“patchValue()”方法并引入了“setValue”方法。
这是有效的 stackblitz 示例:
https://stackblitz.com/edit/angular-conditionaldropdown-gnajge
如果您使用的是 [ngValue]
,则可以在 select
元素上使用 [compareWith]
,通过比较函数来确定是否选择了该值。使用 [ngValue]
允许复杂对象超过 [value]
,这是一个字符串。
<form [formGroup]="customerForm">
<select [compareWith]="compareCustomers" formControlName="customers">
<option>(new customer)</option>
<option [ngValue]="customer" *ngFor="let customer of customers">
{{customer.name}}
</option>
</select>
<select [compareWith]="compareOrders" formControlName="orders">
<option>(new order)</option>
<option [ngValue]="order" *ngFor="let order of filteredOrders">
{{order.id}}
</option>
</select>
</form>
export class SomeComponent {
public compareCustomer(a: Customer, b: Customer): boolean {
return a.id === b.id;
}
public compareOrders(a: Order, b: Order): boolean {
return a.id === b.id;
}
}