es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo agrupar elementos en una lista de Angular Material con subencabezados

Tengo una matriz de objetos que me gustaría mostrar en una lista de selección Mat-Selection-List. Estos objetos tienen dos propiedades, una de las cuales quiero agrupar y usar como subencabezados (foo) y otra que me gustaría listar/mostrar (bar). La lista debe mostrar todos los objetos todo el tiempo (sin filtrar), la clave está en que solo se muestra la propiedad bar y los objetos se agrupan según su propiedad foo, que se utiliza como subencabezado.

La lista debe construirse dinámicamente y eventualmente verse similar a la siguiente:

<mat-list>
  <ng-container *ngfor="cada Foo diferente de la matriz de objetos">
    <div mat-subheader="">foo</div>
    <mat-list-item *ngfor="cada objeto con este foo">
      <div>bar</div>
    </mat-list-item>
  </ng-container>
</mat-list>

Los *ngFors en el código anterior no funcionan y están destinados a mostrar lo que estoy tratando de hacer. ¿Cuál es la forma “Angular” de lograr una lista así a partir de una matriz de objetos? ¿Son las Pipes el camino correcto y, de ser así, cómo deberían ser?

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Para lograr una lista así en Angular, puedes hacer uso de las directivas integradas de Angular como ngFor y ngIf, junto con el componente Mat-Selection-List de Angular Material. Aquí tienes un ejemplo de cómo crear la lista dinámicamente:

    Primero, en el archivo del componente, define el arreglo de objetos que deseas mostrar en la lista:

    myObjects = [
      { foo: 'a', bar: 'manzana' },
      { foo: 'a', bar: 'aguacate'},
      { foo: 'b', bar: 'banana' },
      { foo: 'c', bar: 'cereza' },
      { foo: 'c', bar: 'coco' }
    ];
    

    Luego, en el archivo HTML, utiliza la directiva ngFor para iterar sobre cada valor único de la propiedad foo y mostrarlo como un subencabezado:

    <mat-selection-list>
      <ng-container *ngfor="let group of myObjects | groupBy: 'foo'">
        <div mat-subheader="">{{ group.key }}</div>
        <mat-list-option *ngfor="let obj of group.items">
          {{ obj.bar }}
        </mat-list-option>
      </ng-container>
    </mat-selection-list>
    

    Ten en cuenta que hemos utilizado un Pipe personalizado llamado groupBy para agrupar los objetos según su propiedad foo. Esto es cómo se ve el Pipe groupBy:

    @Pipe({
      name: 'groupBy'
    })
    export class GroupByPipe implements PipeTransform {
      transform(value: any[], key: string): any[] {
        const groups = value.reduce((acc, obj) => {
          const property = obj[key];
          acc[property] = acc[property] || [];
          acc[property].push(obj);
          return acc;
        }, {});
        return Object.entries(groups).map((entry) => {
          return {
            key: entry[0],
            items: entry[1]
          };
        });
      }
    }
    

    El Pipe toma un arreglo de objetos y una clave para agrupar. Retorna un nuevo arreglo de objetos, donde cada objeto tiene una propiedad key (el valor de la clave agrupada) y una propiedad items (un arreglo de todos los objetos que tienen ese valor de clave). El Pipe se usa en el archivo HTML de la siguiente manera:

    <ng-container *ngfor="let group of myObjects | groupBy: 'foo'">
    

    Esto agrupará los objetos por su propiedad foo y creará un nuevo arreglo de grupos, cada uno conteniendo un arreglo de objetos con el mismo valor de foo.

Comments are closed.