4

I am working on angular selectionmodel where I have a search bar where user searches for list and selects items and if user closes the search keyword then previous selected values i.e., before search not getting selected in the selectionmodel list.

Search code in ts:

searchUsers(filterValue: string) {
  this.previousSelectedValues = this.userSelection.selected;
  console.log("came to searchUsers",filterValue);
  this.searchKey = filterValue;
  let params = { 'searchData': this.searchKey}
  this.commCenterService.getSearchedUsers(params).subscribe((res)=>{
    console.log("Search Response: Users",res);
    this.users = res;
    console.log("previous selected fields",this.userSelection.selected);
    if(filterValue == ""){
     this.previousSelectedValues.forEach(row => this.userSelection.select(row));
    }
    this.dataSource = new MatTableDataSource(this.users);
   });
}

selectionmodel initialization code:

userSelection = new SelectionModel<AddRecipientsList>(true, []);
/** Whether the number of selected elements matches the total number of rows. */
isAllSelected() {
  const numSelected = this.userSelection.selected.length;
  const numRows = this.dataSource.data.length;
  return numSelected === numRows;
}
/** Selects all rows if they are not all selected; otherwise clear selection. */
masterToggle() {
  this.isAllSelected() ?
  this.userSelection.clear() :
  this.dataSource.data.forEach(row => this.userSelection.select(row));
}
/** The label for the checkbox on the passed row */
checkboxLabel(row?: PeriodicElement): string {
 if (!row) {
  return `${this.isAllSelected() ? 'select' : 'deselect'} all`;
 }
}

HTML:

<div fxFlex="auto" fxLayoutAlign="start center" fxLayoutGap="10px">
  <mat-form-field fxFlex="100" appearance="outline">
    <input matInput type="text" (keydown.enter)="searchUsers(value)" [(ngModel)]="value">
    <mat-label fxLayoutAlign="start center">
     <mat-icon class="s-16">search</mat-icon>Search by Recipient Name, Email
    </mat-label>
    <button mat-button *ngIf="searchKey" matSuffix mat-icon-button aria-label="Clear" (click)="value=''; searchUsers(value);">
                <mat-icon class="s-16">close</mat-icon>
    </button>
 </mat-form-field>
</div>    

<div>
  <mat-table [dataSource]="dataSource" class="display-table">
    <!-- Checkbox Column -->
    <ng-container matColumnDef="select">
     <mat-header-cell *matHeaderCellDef>
      <mat-checkbox (change)="$event ? masterToggle() : null"
                  [checked]="userSelection.hasValue() && isAllSelected()"
                  [indeterminate]="userSelection.hasValue() && !isAllSelected()" [aria-label]="checkboxLabel()">
      </mat-checkbox>
     </mat-header-cell>>
     <mat-cell *matCellDef="let row">
       <mat-checkbox (click)="$event.stopPropagation()" (change)="$event ? userSelection.toggle(row) : null"
                  [checked]="userSelection.isSelected(row)" [aria-label]="checkboxLabel(row)">
       </mat-checkbox>
     </mat-cell>>
    </ng-container>
    <!-- recepientName Column -->
    <ng-container matColumnDef="recepientName">
     <mat-header-cell *matHeaderCellDef> recepient Name </mat-header-cell>
       <mat-cell *matCellDef="let element"> {{element.name}} </mat-cell>
    </ng-container>
    <!-- recepientEmail Column -->
    <ng-container matColumnDef="recepientEmail">
     <mat-header-cell *matHeaderCellDef> recepient Email </mat-header-cell>
       <mat-cell *matCellDef="let element"> {{element.email}} </mat-cell>
     </ng-container>
     <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
     <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
  </mat-table>
</div>

I am able to get my previous selected list from this.userSelection.selected

My selection/previous selected List is below:

previous selected fields 
0:
 email: "email1@example.com"
 name: "some name" 
1:
 email: "email2@example.com"
 name: "some name"

How does this work? Any Idea? Thanks.

Prasad Patel
  • 707
  • 3
  • 16
  • 53

1 Answers1

11

SelectionModel holds references to objects. Therefore when you re-initialize this.dataSource in searchUsers function, references to actual objects in this.userSelection gets lost. In order to overcome this in your use case you have to re-initialize this.userSelection with new objects in new this.dataSource

However, since your search returns different lists; it may not be possible to find previous user items in new search results. In this case i suggest using a primitive value (which acts as a unique id for user objects) for keeping elements in SelectionModel. Such that;

selection.toggle(row.email) /** when selecting/de-selecting elements*/

and

selection.isSelected(row.email) /** when checking if an element is selected */

Please note that; i suggest removig master toggle to select/unselect all elements because your list changes at every search and selecting/unselecting all in different lists seems a bit ambiguous in a user point of view.

I also created a demo here;

https://stackblitz.com/edit/angular-e9brcp

in your html, update this part

<mat-checkbox (click)="$event.stopPropagation()" (change)="$event ? userSelection.toggle(row) : null" 
    [checked]="userSelection.isSelected(row)" [aria-label]="checkboxLabel(row)">
</mat-checkbox>

to this

<mat-checkbox (click)="$event.stopPropagation()" (change)="$event ? userSelection.toggle(row.email) : null" 
     [checked]="userSelection.isSelected(row.email)">
</mat-checkbox>
ysf
  • 4,634
  • 3
  • 27
  • 29
  • Thanks for the reply but Its not working only the data selected after search getting selected not the before search data getting selected. that means data before search and data after search has to be selected after I close the 'close' button in the search. – Prasad Patel Jun 10 '19 at 15:46
  • For example: If I select 2 items then I search for some item and selects one item then I close the search item then the one item which I selected after search is getting selected but the 2 items selected before the search is not getting selected. I hope I explained my problem clearly..! – Prasad Patel Jun 11 '19 at 07:48
  • i misunderstood your use case about searching. I updated my answer accordingly and created a demo. I hope it helps. – ysf Jun 11 '19 at 07:51
  • Could you please tell where to use those 2 lines of code in my code..! – Prasad Patel Jun 11 '19 at 08:00
  • I updated my question with full html code, please check once again. – Prasad Patel Jun 11 '19 at 08:11
  • Thanks a ton brother. Just changing the html code did the trick, I have removed your previous ts code which you posted in your first answer and kept my old ts code which is in my question. But the select all checkbox is getting (ticked) selected by default after my first search only, when I search second time its working fine that means usually if some item selected then we get '-' symbol in 'select-all' checkbox I am talking about that. – Prasad Patel Jun 11 '19 at 08:38
  • i am glad that it helps. as i stated in my answer, you better remove selectAll checkbox because when you make a search it is not clear which items to select/unselect because your list of users change at every search. it still can be done but requires some boilerplate code which i don't think is necessary. – ysf Jun 11 '19 at 08:44
  • I need 'selectAll' checkbox because that is my requirement. – Prasad Patel Jun 11 '19 at 09:30
  • i updated stackblitz. just change isAllSelected() and masterToggle() functions. if it works can you please upvote the answer. – ysf Jun 12 '19 at 09:55
  • Thanks for your comment. It's very helpful for fixing my issue – Vanitha V Jan 30 '23 at 15:38