4
votes

I try to dynamically add Roles to my User/Roles-application. I have a Formarray where i can show the Roles of the User in the Edit View. And there is a button for adding more Roles to the User. But when i press the button "Add Role", i got this error message:

ERROR Error: Cannot find control with path: 'rolesArr -> 1 -> name'

In this example, i try to add more than one Role to a User that i want to create.

Here is my Code:

users-edit.component.html (excerpt)

<div formArrayName="rolesArr" >
<div class="row">
    <div class="col-md-10 col-md-offset-2">
        <button class="btn btn-default"
                type="button"
                (click)="addRole()">Add Role
        </button>
    </div>
</div>
<br>
<div *ngFor="let role of roles.controls; let i=index">
    <div [formGroupName]="i">

        <div class="form-group">
            <label class="col-md-2 control-label" [attr.for]="i">Role</label>

            <div class="col-md-8">
                <input class="form-control"
                        [id]="i" 
                        type="text" 
                        placeholder="Role" 
                        formControlName="name" />
            </div>
        </div>
    </div>
</div>

users-edit.component.ts (excerpt)

addRole() {
    this.roles.push(this.fb.group(new Roles()));
}

ngOnInit(): void {

    this.userForm = this.fb.group({
        username: ['', [Validators.required, Validators.minLength(3)]],
        firstname: ['', [Validators.required, Validators.minLength(3)]],
        lastname: ['', [Validators.required, Validators.minLength(3)]],
        password: ['', [Validators.required, Validators.minLength(10)]],
        rolesArr: this.fb.array([])
    });

    this.sub = this.activeRoute.params.subscribe(
        params => {
            let id = +params['id']; //converts string'id' to a number
            this.getUser(id);
        }
    );
}
getUser(id: number) {
        this.userService.getUser(id).subscribe(
                user => this.onUserRetrieved(user)
            );
}
onUserRetrieved(user: User): void {
    console.log("OnUserRetrieved: " + user.firstname);
    if (this.userForm) {
        this.userForm.reset();
    }
    this.users = user;

    if (this.users.id === 0) {
        this.pageTitle = 'Add User';
    } else {
        this.pageTitle = `Edit User: ${this.users.username}`;
    }

    //Update the data on the form
    this.userForm.patchValue({
        username: this.users.username,
        firstname: this.users.firstname,
        lastname: this.users.lastname,
        password: this.users.password
    });

    const roleFGs = this.users.roles.map(roles => this.fb.group(roles));
    const roleFormArray = this.fb.array(roleFGs);
    this.userForm.setControl('rolesArr', roleFormArray);
}

What am i doing wrong?

2

2 Answers

2
votes

You should create a form group with the controls for Roles as below,

createRole() :  FormGroup {
    return this.fb.group({
            name: '',
            type: '',

    });
}

Then you should push the role as below,

addRole() {
    this.roles.push(this.createRole());
}
1
votes

While Aravind's answer works you are still able to do the exact same thing you are doing now:

addRole() {
    this.roles.push(this.fb.group(new Roles()));
}

but the control requires default values for your properties in the class (which is exactly what Aravind's solution does, it creates an object with default values)

so if your current Roles class looks something like this:

export class Roles {
    public name: string;
    public type: string;
}

you should add default values like this:

export class Roles {
    public name: string = '';
    public type: string = '';
}

This allows angular to find your properties as control's

Additional information: https://angular.io/guide/reactive-forms#use-formarray-to-present-an-array-of-formgroups