user7974621
user7974621

Reputation:

How to include a search/filter box in mat-select

Brief summary:

I have a mat-dialog whose purpose is to create/edit/delete "equipos" (hardware) and all of it's components and save the information on my database. Inside of it there's several dynamically built mat-select fields in charge of adding or removing "dispositivos" (devices) from said hardware.


The issue:

The amount of options some of the dynamic select fields retrieve is absurdly large, so I need to implement some sort of filter for users to navigate all these options easily.


My attempt:

I've been trying to use the mat-select-filter library but I don't know how to fully implement it on my use-case.

HTML:

<div *ngFor="let clase of dispositivosByClases; index as i;" formArrayName="dispositivosForm">
    <div [formGroupName]="i">
        <div>
            <mat-form-field *ngIf="tabImpresoraEscaner.includes(clase.nombre)" class="dispositivo">
                <mat-select (selectionChange)="checkForm()" formControlName="dispositivos"
                    placeholder="{{clase.nombre}}" multiple>
                    <mat-select-filter (filteredReturn)="filteredList =$event" [array]="clase.dispositivos"
                        [displayMember]="'descripcion'" [placeholder]="'Filtrar'"></mat-select-filter>
                    <mat-option *ngFor="let dispo of clase.dispositivos" [value]="dispo.id">
                        {{ dispo.descripcion }}
                    </mat-option>
                </mat-select>
            </mat-form-field>
        </div>
    </div>
</div>

TS:

prepareClaseDispositivo() {
    this.dispositivos.forEach(dispo => {
        if (!this.labelDispositivos.includes(dispo.clase_dispositivo.nombre)) {
            this.labelDispositivos.push(dispo.clase_dispositivo.nombre);
        }
    });
    this.labelDispositivos.forEach(clase => {
        this.dispositivosForm.push(this.generateFormGroup([], clase));
        const dispositivosByClase = [];
        this.dispositivos.forEach(dispo => {
            if (clase === dispo.clase_dispositivo.nombre) {
                dispositivosByClase.push(dispo);
            }
        });
        this.filteredList[clase] = dispositivosByClase.slice();
        this.dispositivosByClases.push({ nombre: clase, dispositivos: dispositivosByClase });
    });
    if (this.data.edit) {
        this.populateFormGroup();
    }
}

The issue here is that in order to make it work I need to replace

<mat-option *ngFor="let dispo of clase.dispositivos" [value]="dispo.id">
    {{ dispo.descripcion }}
</mat-option>

with

<mat-option *ngFor="let filteredOptions[clase] of clase.dispositivos" [value]="item">
    {{ item.descripcion }}
</mat-option>

But clase.dispositivos is in charge of pre-selecting all devices a hardware has stored in it's database entry, so that's not an option.

If you need to see any other part of the codebase or need me to clarify anything please let me know.

Upvotes: 1

Views: 1435

Answers (2)

user7974621
user7974621

Reputation:

Managed to stumble upon the issue.

<mat-select (selectionChange)="checkForm()" formControlName="dispositivos" placeholder="{{clase.nombre}}" multiple>
    <mat-select-filter (filteredReturn)="filteredList[clase.nombre] =$event" [array]="clase.dispositivos"
        [displayMember]="'descripcion'" [placeholder]="'Filtrar'"></mat-select-filter>
    <mat-option *ngFor="let dispo of filteredList[clase.nombre]" [value]="dispo.id">
        {{ dispo.descripcion }}
    </mat-option>
</mat-select>

On (filteredReturn) I wasn't navigating the object correctly, it should've been:

(filteredReturn)="filteredList[clase.nombre] =$event"

Instead of:

(filteredReturn)="filteredList =$event" 

Then replacing clase.dispositivos with filteredList[clase.nombre] on the option's ngFor did the rest.

Upvotes: 1

G. Tranter
G. Tranter

Reputation: 17918

What you need is a Pipe. You syntax would look something like (pseudo-code):

<mat-select ...>
    <mat-option *ngFor="let dispo of (clase.dispositivos | dispoPipe)" [value]="dispo.id">
        {{ dispo.descripcion }}
    </mat-option>
</mat-select>

...

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'dispoPipe' })
export class DispoPipe implements PipeTransform {

    transform(allDispos: Dispo[]) {
        return allDispos.filter(dispo => ???);
    }
}

Upvotes: 0

Related Questions