0

A component gets (via @Input()) 2 arrays: "users"

[{Id: 1, Name: 'One'}, {Id: 2, Name: 'Two'}, {Id: 3, Name: 'Three'}]

and "selectedUsers":

[{Id: 2, Name: 'Two'}]

and outputs items on a page: One Two Three

"Two" - is highlighted as it is contained in array "selectedUsers". How to add item from "users" array to "selectedUsers" and vice versa by click (and highlight clicked item)?

Parent component:

users = [
    {Id: 1, Name: 'One'}, 
    {Id: 2, Name: 'Two'}, 
    {Id: 3, Name: 'Three'}
];

usersSelected = [
    {Id: 2, Name: 'Two'}
];

HTML:

<app-item (*ngFor="let u of users", [user]="u")></app-item>

Child component:

@Input() user;
isActive: boolean = false;
toggleClass(){
    this.isActive = !this.isActive;
}

HTML

<p [class.active]="isActive" (click)="toggleClass()">{{user.Name}}</p>

Here's another try but it should be done with @Input/@Output: https://plnkr.co/edit/cjaij4aQuvN4Tk4ZE0ez?p=preview

5
  • (*ngFor="let u of users", [user]="u") is totaly impossible. First : if you want to update isActive in parent you only need: one input "isActive" that you will update and one output "isActiveChange" (EventEmiter), that you will emit each time you update isActive. the "Change" end is really important ! you will be able to use with [(isActive)]="whereYouWantPutBoolean" Commented Feb 21, 2018 at 19:44
  • Why is (*ngFor="let u of users", [user]="u") is totaly impossible? Then how to output list? Commented Feb 21, 2018 at 19:49
  • Why do you need 2 arrays? Just extend the user type with a property named selected of type boolean (true/false). That is cleaner/easier to use then copying/removing users between the 2 arrays. Also I do not believe that is valid template syntax in your html. Commented Feb 21, 2018 at 19:50
  • I'm looking at your plunker and you have types error. To you use tslint ? selectedPerson must bu an array of person (as you init it in constructor) so there is no name on the array and you can not do "this.selectedPerson = person;" but you can do "this.selectedPerson.push(person);" Commented Feb 21, 2018 at 19:51
  • You can only refer to EventEmiter in (). *ngFor="let u of users", [user]="u" is not a reference so it's an invalid syntax. Commented Feb 21, 2018 at 19:55

2 Answers 2

1

If you like to use two arrays and a parent and child component:

https://plnkr.co/edit/uEKeMRMpLnoR49clxCfo?p=preview

@Component({
  selector: 'my-parent',
  template: `
    <my-child [users]="users" [selected]="selected" ></my-child>
  `,
})
export class ParentComponent {
  public users = ['one', 'two', 'three'  ];
  public selected = [];
}

@Component({
  selector: 'my-child',
  template: `
    <div *ngFor="let user of users">
      <p [ngClass]="{ selected: isSelected(user) }" (click)="clickOnUser(user)">{{user}}</p>
    </div>
  `,
  styles: [`
    .selected {
      color: red;
    }
  `]
})
export class ChildComponent {

  @Input()
  public users: string[];

  @Input()
  public selected: string[];

  public isSelected(user) {
    return this.selected.indexOf(user) !== -1;
  }

  public clickOnUser(user) {
    if (this.selected.indexOf(user) !== -1) {
      this.selected.splice(this.selected.indexOf(user), 1);
    } else {
      this.selected.push(user);
    }
  }

}
Sign up to request clarification or add additional context in comments.

2 Comments

Your variant is very close to the desired result! Could you make a hint, how to add @Input/@Output here? I've added @Input() user; @Input() selected; @Input() isSelected; @Input() clickOnUser; to child, added publics to parent, but there's an error "isSelected is not a function"
An additional hint. If you don't want to pass the functions clickOnUser and isSelected to the child component. Then it is not required to add @Input()
1

Why do you need 2 arrays? Just extend the user type with a property named selected of type boolean (true/false). That is cleaner/easier to use then copying/removing users between the 2 arrays.

users = [
    {Id: 1, Name: 'One', IsSelected: false}, 
    {Id: 2, Name: 'Two', IsSelected: true}, 
    {Id: 3, Name: 'Three', IsSelected: false}
];

This allows any component that is used for rendering a user in the array to update the IsSelected property directly.

@Input() user;
get isActive(): boolean {return this.user.IsSelected;}

toggleClass(){
    this.user.IsSelected = !this.user.IsSelected;
}

Also I do not believe that is valid template syntax in your html.

2 Comments

Just be aware that you mutate objects.
The thing is that we should bind 2 arrays, that's why here are 2 arrays.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.