0

So I have a page where I will create new user and I'm trying to add ability to specify to what group this user will belong to. I've marked code as bold inside onSubmit function so you can see it, this code will check which group was checked and will set a membership for this new use. So for my app to be able to know which group was checked I used data binding in html [(ngModel)]="item.Selected" and marked that piece of code as bold so you can find it. But it doesn't work and throws an error that I've attached as a screenshot. Thank you!

<div class="tab">

    <h2>Add New User</h2>

    <form (ngSubmit)="onSubmit(addNewUserForm)" #addNewUserForm="ngForm" [hidden]="Error!=null">

        <mat-card>

            <div class="form-group">

                <label for="name"><b>Name</b></label>

                <div>

                    <input autocomplete="off" type="text" id="name" required [(ngModel)]="user.name" name="name"
                        #name="ngModel">

                    <div [hidden]="name.valid" class="alert alert-danger">Name is required</div>

                </div>

            </div>

            <div class="form-group">

                <label for="password"><b>Password</b></label>

                <div>

                    <input type="password" id="password" [(ngModel)]="user.password" name="password"
                        #password="ngModel">

                    <div [hidden]="!passwordEmpty(addNewUserForm)" class="alert alert-warning">Blank password is not
                        recommended</div>

                </div>

            </div>

            <div class="form-group">

                <label for="password2"><b>Retype Password</b></label>

                <div>

                    <input type="password" id="password2" [(ngModel)]="user.password2" name="password2"
                        #password2="ngModel">

                    <div [hidden]="passMatch(addNewUserForm)" class="alert alert-danger">Password does not match</div>

                </div>

            </div>

            <div class="form-group-groups">

                <label><b>Select group</b></label>
            </div>

            <mat-form-field style="min-width: 290px; margin-left: 1em;">

                <mat-select multiple>

                 **<mat-option *ngFor="let item of items" [(ngModel)]="item.Selected">{{item.Name}}</mat-option>**

                </mat-select>

            </mat-form-field>

        </mat-card>

        <mat-card>

            <button mat-raised-button class="lspace" [disabled]="!formValid(addNewUserForm)">Add</button>
            <button mat-raised-button class="lspace" (click)="onCancel()">Cancel</button>

        </mat-card>

    </form>

    <div>

        <p class="error" *ngIf="Error != null">{{Error}}</p>

    </div>

</div>

export class UserDetails {
    name: string;
    password: string;
    password2: string;
}

export module Model {
    export class GroupItem {
        constructor(group: Group) {
            this.Name = group.Name;
            this.Selected;
        }

        readonly Name: string;
        Selected: boolean;
    }
}

@Component({
    selector: 'new-user',
    templateUrl: './user-new.component.html',
    styleUrls: ['./user-new.component.css'],
})

export class NewUserComponent extends BaseComponent implements OnInit {
    user: UserDetails;
    Groups: Group[];
    items: Model.GroupItem[];

    constructor(appData: AppData, private userService: UsersService, logonService: LogonService, private location: Location, private groupService: GroupsService) {
        super(appData, logonService);
        this.user = new UserDetails();
    }


    protected onToken(token: string): void {
        this.fetchGroups(token);
    }

    private fetchGroups(token: string): void {
        this.groupService.getGroups(token).subscribe(
            groups => { this.buildItems(groups) },
            (err: any) => { this.showError(err) }
        );
    }

    private buildItems(groups: Group[]): void {
        this.items = new Array<Model.GroupItem>(groups.length);
        for(let i=0; i < groups.length; ++i) {
            this.items[i] = new Model.GroupItem(groups[i]);
        }
    }

    ngOnInit() {
        super.ngOnInit();
        document.getElementById('name').focus();
    }

    onCancel(): void {
        super.ngOnInit();
        this.location.back();
    }

    passMatch(form: NgForm): boolean {
        let p1 = (form.value.password == null) ? '' : form.value.password;
        let p2 = (form.value.password2 == null) ? '' : form.value.password2;
        return (p1 == p2);
    }

    formValid(form: NgForm): boolean {
        return form.valid && this.passMatch(form);
    }

    passwordEmpty(form: NgForm): boolean {
        return (form.value.password == null) || (form.value.password.length == 0);
    }

    onSubmit(form: NgForm): void {
        if (this.Token == null || this.Token == '') {
            console.error('Token is not valid.');
            return;
        }

        **var groups: string[] = this.items.filter(itm => itm.Selected).map(itm => itm.Name);
        this.userService.setMembership(this.Token, this.user.name, groups).subscribe(
            () => { this.location.back(); this.appData.setDirty(); },
            (err: any) => { this.showError(err) }
        );**
        //
        let pass = (this.user.password == '') ? null : this.user.password;
        this.userService.addUser(this.Token, this.user.name, pass).subscribe(
            (_: string) => { this.location.back(); this.appData.setDirty(); },
            (err: any) => { this.showError(err); }
        );
    }
}

My app with error that I get

urasavidi
  • 103
  • 1
  • 6

1 Answers1

0

You have no name attribute on your mat-select and the way you're using mat-select seems a bit off. Your model should probably be on the mat-select but I'd have to see what your items object looks like. You want something closer to this though I believe:

<mat-select multiple [(ngModel)]="selectedItem">
**<mat-option *ngFor="let item of items" [value]="item.id">{{item.Name}}</mat-option>**
</mat-select>

abney317
  • 7,760
  • 6
  • 32
  • 56
  • Thank you for your comment. I've tried adding name like in the code that you've attached, but still same error. Is there anything else that has to be added maybe? – urasavidi Nov 01 '19 at 15:40
  • Add it to your mat-option I suppose since that is where the ng-model is being used. Would be easier to test with a stackblitz included – abney317 Nov 01 '19 at 15:47
  • I believe your ngModel should actually be on your mat-select, not the options – abney317 Nov 01 '19 at 15:53
  • It was throwing new error "Error: No value accessor for form control with name: 'group' " And I had to add ngDefaultControl like it says here and it did the trick: https://stackoverflow.com/questions/38958347/angular2-rc-5-custom-input-no-value-accessor-for-form-control-with-unspecified Thank you very much! – urasavidi Nov 01 '19 at 15:59