How to use PrimeNG multiselect search to trigger an API call based on user search input and populate the multiselect with the retrieved data?

45 views Asked by At

When ever we enter text in the filter section, we need to call an API to get the relevant output list and update this into multiselect results.

Here I tried onFilter event to call the API, I got the API result but the result list not getting updated in the multiselect DOM. I can not override the default filter result. When I do next keypress then the filtering happening based on my last result.

html code:

<p-multiSelect
          class="add-more-permission-modal__container__filter"
          [options]="permissions"
          [(ngModel)]="selectedPermission"
          [autofocusFilter]="true"
          optionLabel="label"
          styleClass="es-multi-select es-multi-select--filter es-multi-select--no-scroll w-full"
          [resetFilterOnHide]="true"
          placeholder="Select permission of any department"
          appendTo="body"
          (onFilter)="onKeyUp($event)"
        ></p-multiSelect>

ts code:

import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  EventEmitter,
  Input,
  OnInit,
  Output
} from '@angular/core';
import { AddAdminUserPermission } from 'src/app/compliance/interface';
import { debounceTime, distinctUntilChanged, filter, Subject } from 'rxjs';
import { AdminUserApiService } from '../../../../services/admin-user-api.service';

@Component({
  selector: 'es-admin-add-more-permission',
  templateUrl: './add-more-permission.component.html',
  styleUrls: ['./add-more-permission.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AddMorePermissionComponent implements OnInit {

  public filterInput$ = new Subject<string>();
  public permissions: AddAdminUserPermission[] = [];
  selectedPermission: AddAdminUserPermission[];

  constructor(
    private adminUserService: AdminUserApiService,
    private cdr: ChangeDetectorRef
  ) {}

  ngOnInit(): void {
    this.filterInput$
      .pipe(
        debounceTime(300),
        distinctUntilChanged(),
        filter((query) => query?.length >= 3)
      )
      .subscribe((filterValue) => {
        console.log(filterValue);

        this.adminUserService.filterPermission(filterValue).subscribe((res) => {
          this.permissions = res;
          console.log('searched permissions: ', this.permissions);
          this.cdr.detectChanges();
        });
      });
  }

  onKeyUp($event: any) {
    this.filterInput$.next($event.filter);
  }
}


service code:

@Injectable({
  providedIn: 'root'
})
export class AdminUserApiService {
  constructor() {}
  filterPermission(filterPermissionParams: string) {
    console.log('filter permission called');

    const permissions: PermissionDto[] = [
      {
        id: 101,
        name: 'Permission 101',
        departmentResponse: {
          id: 2,
          name: 'Engineering Department'
        }
      },
      {
        id: 102,
        name: 'Permission 102',
        departmentResponse: {
          id: 2,
          name: 'Engineering Department'
        }
      },
      {
        id: 103,
        name: 'Permission 103',
        departmentResponse: {
          id: 2,
          name: 'Engineering Department'
        }
      },
      {
        id: 104,
        name: 'Permission 104',
        departmentResponse: {
          id: 3,
          name: 'Bank Department'
        }
      },
      {
        id: 105,
        name: 'Permission 105',
        departmentResponse: {
          id: 3,
          name: 'Bank Department'
        }
      }
    ];
    const permissions2: PermissionDto[] = [
      {
        id: 201,
        name: 'Permission 201',
        departmentResponse: {
          id: 5,
          name: 'Engineering Department 2'
        }
      },
      {
        id: 202,
        name: 'Permission 202',
        departmentResponse: {
          id: 5,
          name: 'Engineering Department 2'
        }
      },
      {
        id: 205,
        name: 'Permission 205',
        departmentResponse: {
          id: 8,
          name: 'Bank Department 2'
        }
      }
    ];
    if (filterPermissionParams === 'cat') {
      return of(permissions);
    } else if (filterPermissionParams === 'cats') {
      return of(permissions2);
    } else {
      return of([]);
    }
  }
}

1

There are 1 answers

1
Eliseo On

It's looks like work, the only is filter the value when you received the new values

this.filterInput$
  .pipe(
    debounceTime(300),
    distinctUntilChanged(),
    filter((query) => query?.length >= 3),
  )
  .subscribe((filterValue) => {
    this.adminUserService.filterPermission(filterValue).subscribe((res) => {
      this.permissions = res.map(x=>({label:x,value:x}));
      //here you filter the "selectedPermisions"
      if (this.selectedPermission)
          this.selectedPermission=this.selectedPermission
                                    .filter(x=>res.includes(x.label))

      //this.cdr.detectChanges(); <--it's not necessary
    });
  });

NOTE: you can also define an observable like

  permissions$=this.filterInput$
  .pipe(
    debounceTime(300),
    distinctUntilChanged(),
    filter((query) => query?.length >= 3),
    switchMap((query)=>
      this.adminUserService.filterPermission(query).pipe(
        map((res:string[])=>{
          if (this.selectedPermission)
          this.selectedPermission=this.selectedPermission
                              .filter(x=>res.includes(x.label))
          return res.map(x=>({label:x,value:x}))
      })))

  )

And use

<p-multiSelect
      class="add-more-permission-modal__container__filter"
      [options]="(permissions$|async) || undefined"
      ...
</p-multiSelect>

See stackblitz