typescript Angular 6 Reactive Forms - 按条件动态设置 <select> FormControl 的选定 <option>

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/52387269/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 07:58:20  来源:igfitidea点击:

Angular 6 Reactive Forms - Set the selected <option> of a <select> FormControl dynamically by condition

typescriptangular6angular-reactive-forms

提问by PHilgarth

I need to know how I set the selected <option>of a <select>FormControl dynamically by condition.

我需要知道如何按条件动态设置FormControl的选定<option><select>

Let's say we have customers with orders. There is a dropdown menu where we select a customer and depending on that customer the options for the orders dropdown menu should be set dynamically and a specific order should be selected.

假设我们有客户有订单。有一个下拉菜单,我们可以在其中选择一个客户,根据该客户,应该动态设置订单下拉菜单的选项并选择一个特定的订单。

Also both dropdown menus have an <option>“(new customer/order)” in case there is not yet a customer or an order, so if we route to that form without having a customer, this “new” option should be selected in both drop down menus. If we have a customer without orders, the “new” option should be selected in the orders dropdown menu.

此外,两个下拉菜单都有一个<option>“(新客户/订单)”,以防还没有客户或订单,因此如果我们在没有客户的情况下路由到该表单,则应在两个下拉菜单中选择此“新”选项菜单。如果我们的客户没有订单,则应在订单下拉菜单中选择“新建”选项。

This is the form.component.html:

这是 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>

This is the form.component.ts:

这是 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;
}

Currently I'm routing to the form and provide an id with the url. The customer dropdown menu selects the correct customer depending on the id in the url.

目前我正在路由到表单并提供一个带有 url 的 id。客户下拉菜单根据 url 中的 id 选择正确的客户。

However, the order dropdown menu is only populated correctly, but the selection does not work. No option at all is selected.

但是,订单下拉菜单仅正确填充,但选择不起作用。根本没有选择任何选项。

If I replace the value in this statement:

如果我替换此语句中的值:

this.customerForm.patchValue({ orders: this.filteredOrders[0].id }

this.customerForm.patchValue({ orders: this.filteredOrders[0].id }

with the "(new order)"string already specified in the html:

使用"(new order)"已在 html 中指定的字符串:

this.customerForm.patchValue({ order: "(new order)" })

this.customerForm.patchValue({ order: "(new order)" })

it works. The string "(new order)"is selected in the orders dropdown menu. It just don't work for the filteredOrders.

有用。该字符串"(new order)"是在订单下拉菜单中选择的。它只是不适用于filteredOrders。

What am I doing wrong here? Do I maybe need a whole different approach here?

我在这里做错了什么?我可能需要一种完全不同的方法吗?

回答by PHilgarth

Okay, after a couple of hours I got it. Here are my updated .html and .ts files for your interest:

好的,几个小时后我得到了它。以下是我更新的 .html 和 .ts 文件,供您参考:

HTML:

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

.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);
  }
}

As you can see, in the HTML i now use "[value]" instead of "[ngValue]" and "customer.name" / "order.id" instead of only "customer" / "order".

如您所见,在 HTML 中,我现在使用“[value]”而不是“[ngValue]”和“customer.name”/“order.id”,而不是仅使用“customer”/“order”。

In the .ts-file I got rid of the "patchValue()" method and brought in the "setValue" method.

在 .ts 文件中,我去掉了“patchValue()”方法并引入了“setValue”方法。

Here is the working stackblitz-example:

这是有效的 stackblitz 示例:

https://stackblitz.com/edit/angular-conditionaldropdown-gnajge

https://stackblitz.com/edit/angular-conditionaldropdown-gnajge

回答by RoadEx

I think that the problem comes from the object that is selected in the order selector (also in the customers one, in fact).

我认为问题来自在订单选择器中选择的对象(实际上也是在客户中)。

<option [ngValue]="order" *ngFor="let order of filteredOrders">
    {{order.id}}
</option>

This means that the whole orderobject will be selected and not only the order id. In this case, if you try to patch the value only with the order.id, then it won't work : the selector wait for an Orderobject, not the order.id.

这意味着order将选择整个对象,而不仅仅是订单 ID。在这种情况下,如果您尝试仅使用 修补值order.id,那么它将不起作用:选择器等待Order对象,而不是order.id

I put together a quick stackblitz with a working version of the code you put in the question: https://stackblitz.com/edit/angular-drop-dowb. The only real difference is that

我将一个快速的 stackblitz 与您在问题中提供的代码的工作版本放在一起:https://stackblitz.com/edit/angular-drop-dowb 。唯一真正的区别是

this.customerForm.patchValue({
    orders: this.filteredOrders[0]
});

is used instead of

被用来代替

this.customerForm.patchValue({
    orders: this.filteredOrders[0].id }
});

Update

更新

So, i've updated the stackblitz.

所以,我更新了stackblitz。

To keep the ordersfield with the correct values along the customer, you'll need to add a (change)in the selectfield.

orders沿保持该字段具有正确的值customer,您需要(change)在该select字段中添加一个。

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

Don't forget to pass the customer idfield as the value instead of the customer- Angular does not seem to like it. With the idvalue then, you'll need to add a updateOrdersfunction in the component.ts.

不要忘记传递 customerid字段作为值而不是customer- Angular 似乎不喜欢它。id然后使用该值,您需要updateOrderscomponent.ts.

  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]);
  }

In the case the idis not in the customers list, then you'll only update the orderswith a nullvalue, corresponding to tyour (new order). And if the idis in the customers list, then you'll update the filteredOrders.

如果id不在客户列表中,那么您将只使用ordersnulltyour 相对应的值更新(new order)。如果id是在客户列表中,那么您将更新filteredOrders.