C
C
cocomuffin2019-07-01 15:49:15
Angular
cocomuffin, 2019-07-01 15:49:15

How to properly reset FormControl?

Good day!
I study reactive forms. Explain, please, what exactly in the form reset of the control does not work quite as expected?
There is the following component:

@Component({
  selector: 'my-app',
  template: `
<form [formGroup]="addUserForm">
 <fieldset>
   <label for="user" class="lbl">Add user</label><br>
   <select id="user" (change)="saveName($event.target)"
                *ngIf="notMembers && notMembers.length !== 0"
                [formControl]="addUserForm.controls['userID']">
     <option *ngFor="let user of notMembers"
                value="{{user.id}}">{{user.name}}</option>
    </select>
    <div *ngIf="bool">
      <label for="userRoleID" class="lbl">With role:</label><br>
      <select id="userRoleID" [formControl]="addUserForm.controls['userRoleID']">
        <option value="1">Admin</option>
        <option value="2">Writer</option>
        <option value="3">Reader</option>
      </select>
     </div>
     <div *ngIf="members && members.length !== 0">
       <p class="lbl">Chosen users:</p>
         <div id="usersArray">
            <span class="addedTopicUser" *ngFor="let member of members">{{member.key.name}}<span (click)=deleteUserFromMembers(member.key.id)> (X) </span><br></span>
         </div>
      </div>
    </fieldset>
</form>
`
})
class AppComponent {
  addUserForm: FormGroup;
  notMembers = [{ name: 'User1', id: 1 }, { name: 'User2', id: 2 }, { name: 'User3', id: 3 }];
  members = [];
  bool = false;
  tmpName: string;
  
  constructor() {}
  
  ngOnInit() {
    this.initForm();
  }
  
  initForm() {
    this.addUserForm = new FormGroup({
      userID: new FormControl(null),
      userRoleID: new FormControl(null)
    });
    
    const userID$ = this.addUserForm.controls['userID'].valueChanges;
    const userRoleID$ = this.addUserForm.controls['userRoleID'].valueChanges;
    
    userID$.subscribe(state => {
      this.bool = !!state;
    });

    userRoleID$
      .pipe(
        withLatestFrom(userID$)
      )
      .subscribe(res => {
        const [roleId, userId] = res;
        if (userId === null || roleId === null) {
          return;
        }
        this.addUser(userId, roleId);
        this.addUserForm.controls['userID'].reset();
        this.addUserForm.controls['userRoleID'].reset();
      });
  }
  
  addUser(userId: number, roleId: number) {
    const newUser = {
      key: {
        id: +userId
        name: this.tmpName,
      },
      value: {
        id: +roleId,
      },
    };
    this.notMembers = this.notMembers.filter((member: User) => +member.id !== +userId);
    this.members.push(newUser);
  }
  
  saveName(target) {
    const {innerHTML: name} = target.selectedOptions[0];
    this.tmpName = name;
  }
  
  deleteUserFromMembers(id) {
    const memberToDelete = this.members.find(member => +member.key.id === +id);
    this.members = this.members.filter(member => +member.key.id !== +id);
    this.notMembers.push(memberToDelete.key);
  }
}

The bottom line is that the user selects a user from the list, then selects a role for this user and the pair "user id - role id" is written to the array. Next, the selected user should be removed from the notMembers array (i.e., there is one less option in the select user too) and added to the members array, and the user and role selection controls should return to the initial state of null. Everything is ok with arrays, the data moves correctly, but with the control it's bad luck - after reset() select is not empty, but has the value of the first option, while the control itself has classes ng-valid ng-untouched ng-pristine - i.e. it seems to be reset, but at the same time not null.
Everything works as expected, only if this piece of code
this.addUserForm.controls['userID'].reset();
this.addUserForm.controls['userRoleID'].reset();

change to this one:
setTimeout(() => this.addUserForm.controls['topicUserId'].reset(), 0);
setTimeout(() => this.addUserForm.controls['topicUserRole'].reset(), 0);

Obviously, the matter is in the sequence of code execution, but I don’t understand what exactly is executed before, and before what action. If I understand everything correctly, then the control is reset first, and then, because. with option are dynamic, and depend on the notMembers array, they are redrawn after the controls have been reset.
However, it does not work, everything works fine here, as expected. The only difference is that on the code pen there is only a piece of the component of interest and the piece of code associated with this (i.e. the component itself is about 2 times larger), well, the data does not come from the server, but is locked (but the data will be received before than the user starts to poke something there ...). Why then does it work as expected?

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question