0

I would like to add an item to an array whenever a check box is checked in *ngFor I am looking for a neat way of doing this without too much code or using a component method. I know this used to be really easy in angular version 1

<tr *ngFor="let this_user of RoleUsers.Users">
    ...
    <input type="checkbox" class="custom-control-input" [(ngModel)]="UsersToRemove.Users[this_user.id]" /> <!--[(ngModel)]="" --> <!-- ng-false-value="expression"-->
    ..
</tr>

For this code I get the error ERROR TypeError: Cannot read property '13' of undefined so I think I am very close.

At the moment I am using the user ids to track the keys but if I could have a nice array. If this is not possible without a component method please provide an example.

Update I have managed to get this working with fewer code;

<input type="checkbox" class="custom-control-input" (change)="AddOrRemoveUser(this_user, $event.target.checked)" />

Then the method;

AddOrRemoveUserToRemove (user, checked) {
    console.log ("Remove or add: ", user, checked);
}

I think this this the quickest way to do it.

The UsersToRemove object looks like this;

class UsersToRemove {
    Users: any[];
    InAction: boolean = false;
}

This is attached to the actual component.

  • Can you post the Typescript for UsersToRemove.Users... At a glance that appears to be a static from you use of upper/lower case... – JGFMK Jul 18 '17 at 17:04
  • 1
    Best practice to work with form is to use reactive form. https://angular.io/guide/reactive-forms I advise you to found in this direction. – Smiranin Jul 18 '17 at 17:12
  • This is just a table not a form. It has just 1 checkbox in a loop and a "Remove selected" button. I think that will be more work to use reactive forms –  Jul 18 '17 at 17:14
  • right so you'd have needed an instance of UsersToRemove and call this.instance.Users[this_user_id] to bind to [(ngModel)] surely. – JGFMK Jul 18 '17 at 17:34
  • That does not work. I get the error `ERROR TypeError: Cannot read property '13' of undefined` –  Jul 18 '17 at 17:35
  • because you have class not an instance.. i.e. no new statement in ngInit... to be able to call this. and the instance name not class should have been in the input element to rhs of = after banana box [(ngModel)] And sometimes you can try elvis operator this.?.property in case something odd is going on too.. – JGFMK Jul 18 '17 at 17:36
  • You mean I should add; ` [(ngModel)]="this.instance.Users[this_user_id]"` ? –  Jul 18 '17 at 17:41
  • No... I'm assuming you've not inlined the html... you can call it usersToRemove = new UsersToRemove() even as a property above constructor and avoid ngInit if you like. Then in html use [(ngModel)]="usersToRemove?.Users[this_user]" (optionally add ? Elvis operator) – JGFMK Jul 18 '17 at 17:44
  • @JGFMK That worked which what I was looking for originally. But when I check a user with an id of 45. I get dirty array with length 45. Which is not a problem since it has just 1 element 45: true. So my problem was not having; UsersToRemove: UsersToRemove = new UsersToRemove () –  Jul 18 '17 at 17:51
  • Well the @Smiranin comment about using reactive-forms allows you to deal with stale data detection. If/when you make transition to convert code be sure to add ReactiveFormsModule instead of FormsModule to your app-module.ts. That caught me out initially. I gave a bit of an incite to it here. https://stackoverflow.com/questions/45165079/angular-2-send-textarea-value-to-a-shared-component/45166499#45166499 But there's far more to it than that... – JGFMK Jul 18 '17 at 17:57
  • Why can't I use this; [(ngModel)]="UsersToRemove.Users[]" Is there something equivalent to this? –  Jul 18 '17 at 18:19

1 Answers1

-1

This worked for me but with too much code. Just to answer my question;

@Component({
    ...
})
export class RoleUsersComponent implements OnInit {
    ..
    UsersToRemove: UsersToRemove = new UsersToRemove
  constructor(
     ...
  ) {
        ...
  }

  ...

    AddOrRemoveUser (user, checked) {
        if (checked==true){
            this.UsersToRemove.AddUser(user)
        }else {
            this.UsersToRemove.RemoveUser(user)
        }
        console.log ("UsersToRemove: ", this.UsersToRemove.Users)
    }
}

class UsersToRemove {
    Users: any[];
    constructor( ) { this.Users = []; }
    InAction: boolean = false;
    AddUser (user): void {
        if (!this.UserExists(user)){
            this.Users.push(user);
        }
    }
    RemoveUser (user): void {
        for (var _i = 0; _i < this.Users.length; _i++) {
            if (this.Users[_i].id==user.id){
                this.Users.splice( _i, 1 )
            }
        }
    }
    UserExists (user): boolean {
        let exists = false;
        for (var _i = 0; _i < this.Users.length; _i++) {
            if (this.Users[_i].id==user.id){
                exists = true;
            }
        }
        return exists;
    }
}

Template:

<tr *ngFor="let this_user of RoleUsers.Users">
  ...
  <th scope="row" *ngIf="UsersToRemove.InAction">
    <label class="custom-control custom-checkbox mb-2 mr-sm-2 mb-sm-0">
      <input type="checkbox" class="custom-control-input" (change)="AddOrRemoveUser (this_user, $event.target.checked)" /> <!--[(ngModel)]="" --> <!-- ng-false-value="expression"-->
      <span class="custom-control-indicator"></span>
    </label>
  </th>
  ...
</tr>