在FormGroup添加后,角度可观察的更新太早了

时间:2018-12-02 03:41:41

标签: angular rxjs

对不起,我什至不确定这是否是我的问题的正确标题。我试图使the code尽可能轻。

基本上,我有一个FormGroups的FormArray,每个FormGroups由一个Angular Material Autocomplete组成。我希望自动完成功能的选项是可观察的,以便每当数组中的一个FormGroups更改时,我就可以更新整个选项列表-基本上,每当选择了一个选项时,我都不希望它能够由数组中的任何其他FormGroup选择。

但是,这就是我对角度的新颖性的体现,我正在更新valueChanges上的选项列表,但是当我在数组上推送新的FormGroup时,我需要一个超时来触发第二个valueChanges,以便完全显示自动填充选项。如果我没有该列表,则该列表不会显示在最近添加的FormGroup中。

这是为什么?

代码为here on stackblitz

只需单击“添加输入”,您将在自动完成功能中看到一个用户列表,但是如果注释掉第72行并单击“添加输入”,则不会在最近添加的表单组中看到该列表。

编辑

通过查看stackblitz上的代码,可以更轻松地查看问题,但是由于我投票不足并且建议关闭,因此这里是组件代码:

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, FormControl, FormArray } from '@angular/forms';
import { switchMap } from 'rxjs/operators';
import { of } from 'rxjs'

const users = [
    {
        id:1,
        name:'user1',
    },
    {
        id:2,
        name:'user2',
    },
    {
        id:3,
        name:'user3',
    }
]

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  usersForm: FormArray;  
  users = users;
  filteredUsers: Observable<any>;
  selectedUsers = [];
  canAddInput = true;

  constructor(private fb: FormBuilder ) {}

  ngOnInit() {
    this.usersForm = this.fb.array([]);

    this
        .usersForm
        .valueChanges
        .subscribe(data => {
            this.selectedUsers = data.map(d => d.userNameSelector).filter(d => !!d);
            this.canAddInput = this.getUnselectedUsers().length !== 0 && this.usersForm.controls.length < this.users.length
        })

    //filtered users is an observable 
    this.filteredUsers = this
        .usersForm
        .valueChanges
        .pipe(
            switchMap(() => of(this.getUnselectedUsers()))
        )

   }

   getUnselectedUsers()
   {
    //console.log(this.users.filter(u => this._isNotSelectedUser(u.name)));
    return this.users.filter(u => this._isNotSelectedUser(u.name));
   }

  _isNotSelectedUser = user => !this.selectedUsers.includes(user)

  addInput() {
    this.usersForm.push(this.fb.group({userNameSelector:null}));

    //why do I need this - it triggers usersForm.valueChanges and filteredUsers is updated, but won't the code work without it why?
    setTimeout(() => this.usersForm.updateValueAndValidity(),1);
  }

  removeInput = idx => this.usersForm.removeAt(idx)

}

和HTML:

    <form class="example-form" [formGroup]='usersForm'>
  <div *ngIf="usersForm.controls">
    <div
      *ngFor="let ctrlName of usersForm.controls; let i = index;" [formGroupName]="i">

      <mat-form-field class="example-full-width">
        <input 
          matInput 
          placeholder="Choose a user" 
          [matAutocomplete]="auto"
          formControlName="userNameSelector"
        >
      </mat-form-field>
      <!-- <span>Your choice is: {{usersForm.get(input.name).value | json}}</span> -->

      <mat-autocomplete #auto="matAutocomplete">
          <mat-option 
            <!-- this async pipe is going to be important here -->
            *ngFor="let user of filteredUsers | async" 
            [value]="user.name"
          >
            <span>{{ user.name }}</span>
          </mat-option>
      </mat-autocomplete>
      <button 
        mat-raised-button 
        color="warn"
        (click)="removeInput(i)"
      >Remove Input</button>
    </div>
  </div>
  <button 
    *ngIf="canAddInput"
    mat-raised-button color="primary"
    (click)="addInput()"
  >Add Input</button>
</form>

0 个答案:

没有答案