Angular Grid Agrupar por

    Um comportamento Group By em uma Tabela Ignite UI for Angular ou Grade de UI cria linhas de dados agrupadas com base nos valores das colunas. O Group By emigxGrid permite visualizar os grupos em uma estrutura hierárquica. As linhas de dados agrupadas podem ser expandidas ou colapsadas, e a ordem de agrupamento pode ser alterada pela interface ou API. Quando a Seleção de Linha está ativada, um seletor de Agrupar por Linha é renderizado na área mais à esquerda da linha de grupo. Caso arowSelection propriedade esteja definida como simples, as caixas de seleção são desativadas e servem apenas como indicação para o grupo onde a seleção é colocada. Se arowSelection propriedade estiver definida como múltipla, ao clicar no seletor Agrupar por linha, todos os registros pertencentes a esse grupo.

    Angular Grid Group By Example

    Este exemplo apresenta os recursos de agrupamento de uma grande quantidade de dados. Arrastar os cabeçalhos de coluna para o topo (área de agrupamento) permite que os usuários vejam os dados da coluna selecionada em uma estrutura hierárquica. Eles podem agrupar por em vários campos arrastando mais cabeçalhos de coluna para o topo. Essas opções de agrupamento são úteis quando você tem tabelas com várias linhas e colunas nas quais os usuários desejam apresentar os dados de uma forma muito mais rápida e visualmente aceitável.

    Initial Grouping State

    É possível definir o agrupamento inicial da grade atribuindo um array de expressões àgroupingExpressions propriedade da grade.

    public ngOnInit() {
        grid.groupingExpressions = [
            { fieldName: 'ProductName', dir: SortingDirection.Desc },
            { fieldName: 'Released', dir: SortingDirection.Desc }
        ];
    }
    

    Agrupar expressões implementa aISortingExpression interface.

    Group By API

    Grouping API

    O agrupamento está disponível através da interface e de uma API robusta exposta pelo componente de grade. Desenvolvedores podem permitir que os usuários finais agrupem os dados da grade por certas colunas, definindo a propriedade degroupable cada coluna paratrue.

    <igx-grid [data]="data">
        <igx-column *ngFor="let c of columns" [field]="c.field" [groupable]="true">
        </igx-column>
    </igx-grid>
    
    public ngOnInit() {
        grid.columns.forEach((column) => {
            column.groupable = true;
        });
    }
    

    Durante o tempo de execução, as expressões são obtidas e configuráveis a partir dagroupingExpressions propriedade. Se você precisar adicionar ou alterar uma expressão existente, também pode usar ogroupBy método com um single ou um array deISortingExpression.

    grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: true });
    
    Note

    Até agora, o agrupamento/classificação funcionava em conjunto. Na versão 13.2, é introduzido um novo comportamento que separa o agrupamento da classificação. Por exemplo - limpar o agrupamento não limpará as expressões de classificação na grade ou vice-versa. Ainda assim, se uma coluna for classificada e agrupada, as expressões agrupadas terão precedência.

    Expand/Collapse API

    Além de agrupar expressões, você também pode controlar os estados de expansão das linhas do grupo. Eles são armazenados em uma propriedade separada doigxGrid componentegroupingExpansionState. Uma linha de grupo é identificada de forma única com base no nome do campo para o qual foi criada e no valor que representa para cada nível de agrupamento. Isso significa que a assinatura de uma interface de estado de expansão é a seguinte:

    export interface IGroupByKey {
        fieldName: string;
        value: any;
    }
    
    export interface IGroupByExpandState {
        hierarchy: Array<IGroupByKey>;
        expanded: boolean;
    }
    

    Assim como aogroupingExpressions definir uma lista deIGroupByExpandState diretamente para ogroupingExpansionState vai mudar a expansão de acordo. Além dissoigxGrid, expõe um método que alterna um grupo pela instância de registro de grupo.

        const groupRow = this.grid.groupsRecords.find(r => r.value === "France");
        const groupRow = this.grid.getRowByIndex(0).groupRow;
        grid.toggleGroup(groupRow);
        groupRow.expanded = false;
    

    Grupos podem ser criados, expandidos (padrão) ou colapsados, e os estados de expansão geralmente conteriam apenas o estado oposto ao comportamento padrão. Você pode controlar se os grupos devem ser criados expandidos ou não através dagroupsExpanded propriedade.

    Select/Deselect all rows in a group API

    Selecionar/Deselecionar todas as linhas de um grupo está disponível através dosselectRowsInGroup métodos da API An.deselectRowsInGroup

    O trecho de código abaixo pode ser usado para selecionar todas as linhas dentro de um grupo usando o método de instânciaselectRowsInGroup de registro de grupo. Além disso, o segundo parâmetro desse método é uma propriedade booleana pela qual você pode escolher se a seleção da linha anterior será eliminada ou não. A seleção anterior é preservada por padrão.

        const groupRow = this.grid.groupsRecords.find(r => r.value === "France");
        const groupRow = this.grid.getRowByIndex(0).groupRow;
        grid.selectRowsInGroup(groupRow);
    

    Se você precisar demarcar todas as linhas de um grupo programaticamente, pode usar odeselectRowsInGroup método.

        const groupRow = this.grid.groupsRecords.find(r => r.value === "France");
        const groupRow = this.grid.getRowByIndex(0).groupRow;
        grid.deselectRowsInGroup(groupRow);
    

    Templating

    Group Row Templates

    A linha de grupo, exceto para a interface do usuário de expansão/recolhimento, é totalmente passível de modelo. Por padrão, ele renderiza um ícone de agrupamento e exibe o nome do campo e o valor que ele representa. O modelo de registro de agrupamento é renderizado em relação tem a seguinte assinatura:

    export interface IGroupByRecord {
        expression: ISortingExpression;
        level: number;
        records: GroupedRecords;
        value: any;
        groupParent: IGroupByRecord;
        groups?: IGroupByRecord[];
    }
    

    Como exemplo, o modelo a seguir tornaria o resumo das linhas do grupo mais detalhado:

    <ng-template igxGroupByRow let-groupRow>
        <span>Total items with value: {{ groupRow.value }} are {{ groupRow.records.length }}</span>
    </ng-template>
    

    Group Row Selector Templates

    Como mencionado acima, a linha de grupo, exceto pela interface de expandir/comover, é totalmente templativa. Para criar um modelo personalizado de seletor Group by row dentro da Grade, declare uma<ng-template> diretiva withigxGroupByRowSelector. A partir do template, você pode acessar a variável de contexto implicitamente fornecida, com propriedades que fornecem informações sobre o estado do Group By Row.

    AselectedCount propriedade mostra quantos dos registros do grupo estão atualmente selecionados, enquantototalCount mostra quantos registros pertencem ao grupo.

    <ng-template igxGroupByRowSelector let-groupByRowContext>
        {{ groupByRowContext.selectedCount }} / {{ groupByRowContext.totalCount  }}
    </ng-template>
    

    AgroupRow propriedade retorna uma referência à linha do grupo.

    <ng-template igxGroupByRowSelector let-groupByRowContext>
        <div (click)="handleGroupByRowSelectorClick($event, groupByRowContext.groupRow)">Handle groupRow</div>
    </ng-template>
    

    AsselectedCount propriedades etotalCount podem ser usadas para determinar se o seletor Agrupar por linha deve ser marcado ou indeterminado (parcialmente selecionado).

    <igx-grid #grid [data]="gridData" primaryKey="ProductID" rowSelection="multiple">
        <!-- ... -->
        <ng-template igxGroupByRowSelector let-context>
            <igx-checkbox
                [checked]=" context.selectedCount > 0 && context.selectedCount === context.totalCount"
                [indeterminate]="context.selectedCount > 0 && context.selectedCount !== context.totalCount">
            </igx-checkbox>
        </ng-template>
    </igx-grid>
    

    Angular Grid Group By with Paging

    As linhas de grupo participam do processo de paginação junto com as linhas de dados. Elas contam para o tamanho de página para cada página. As linhas recolhidas não são incluídas no processo de paginação. Qualquer operação de expansão ou recolhimento força o Paging a recalcular a contagem de páginas e ajustar o índice de página, se necessário. Os grupos que abrangem várias páginas são divididos entre elas. A linha de grupo é visível apenas na página em que começa e não é repetida nas páginas subsequentes. As informações de resumo para linhas de grupo são calculadas com base no grupo inteiro e não são afetadas pelo Paging.

    Angular group by with paging example

    Group By with Summaries

    A integração entre Agrupar por e Resumos é descrita no tópico Resumos.

    Keyboard Navigation

    A interface de agrupamento oferece suporte às seguintes interações de teclado:

    • Para linhas de grupo (o foco deve estar na linha ou na célula de expansão/recolhimento)

      • ALT + DIREITA- Expande o grupo
      • ALT + ESQUERDA- Recolhe o grupo
      • ESPAÇO- seleciona todas as linhas no grupo, se a propriedade rowSelection estiver definida como múltipla
    • Para componentes de grupoigxChip no grupo por área (o foco deve estar no chip)

      • SHIFT + ESQUERDA- move a ficha em foco para a esquerda, alterando a ordem de agrupamento, se possível
      • SHIFT + DIREITA- move o chip em foco para a direita, alterando a ordem de agrupamento, se possível
      • ESPAÇO- altera a direção da classificação
      • DELETE- desagrupa o campo
      • Os elementos separados do chip também são focalizáveis e podem ser interagidos usando a tecla ENTER.

    Angular Grid Custom Group By

    igxGrid permite definir agrupamento personalizado por coluna ou por expressão de agrupamento, que fornece agrupamento com base em uma condição personalizada. Isso é útil quando você precisa agrupar por objetos complexos ou para outros cenários específicos do aplicativo.

    Note

    Para implementar agrupamento personalizado, os dados precisam ser ordenados adequadamente. Por isso, você também pode precisar aplicar uma estratégia de ordenação personalizada que estenda a baseDefaultSortingStrategy. Após a ordenação dos dados, os grupos personalizados podem ser determinados especificando agroupingComparer para a coluna ou para a expressão de agrupamento específica.

    O exemplo abaixo demonstra agrupamento personalizado porDate, onde os valores de data são ordenados e agrupados por Dia, Semana, Mês ou Ano com base no modo de agrupamento selecionado pelo usuário.

    Angular custom group by example

    O exemplo define estratégias de ordenação personalizadas para as diferentes condições de data. Cada estratégia personalizada estende a baseDefaultSortingStrategy e define ocompareValues método, que é a função de comparação personalizada usada ao ordenar os valores. Além disso, extrai os valores da data necessária para a comparação.

    class BaseSortingStrategy extends DefaultSortingStrategy {
    
        public getParsedDate(date: any) {
            return {
                day: date.getDay(),
                month: date.getMonth() + 1,
                year: date.getFullYear()
            };
        }
    
        compareValues(a: any, b: any) {
            const dateA = this.getParsedDate(a);
            const dateB = this.getParsedDate(b);
            return dateA.year < dateB.year ?
                -1 : dateA.year > dateB.year ?
                1 : dateA.month  < dateB.month ?
                -1 : dateA.month > dateB.month ?
                1 : 0;
        }
    }
    
    class DaySortingStrategy extends BaseSortingStrategy {
        compareValues(a: any, b: any) {
            const dateA = this.getParsedDate(a);
            const dateB = this.getParsedDate(b);
            return dateA.year < dateB.year ?
                -1 : dateA.year > dateB.year ?
                1 : dateA.month  < dateB.month ?
                -1 : dateA.month > dateB.month ?
                1 : dateA.day < dateB.day ?
                -1 : dateA.day > dateB.day ?
                1 : 0;
        }
    }
    
    class WeekSortingStrategy extends BaseSortingStrategy {
    
        public getWeekOfDate(a: any) {
           return parseInt(new DatePipe("en-US").transform(a, 'w'), 10);
        }
    
        compareValues(a: any, b: any) {
            const dateA = this.getParsedDate(a);
            const dateB = this.getParsedDate(b);
            const weekA = this.getWeekOfDate(a);
            const weekB = this.getWeekOfDate(b);
            return dateA.year < dateB.year ?
                -1 : dateA.year > dateB.year ?
                1 : weekA < weekB ?
                -1 : weekA > weekB ?
                1 : 0;
        }
    }
    

    UmagroupingComparer função é definida para as expressões de agrupamento, que determina os itens pertencentes ao mesmo grupo com base no modo de agrupamento selecionado. Valores nos dados ordenados para os quais essa função retorna 0 são marcados como parte do mesmo grupo.

     groupingComparer: (a, b) => {
        const dateA = this.sortingStrategy.getParsedDate(a);
        const dateB = this.sortingStrategy.getParsedDate(b);
        if (this.groupByMode === 'Month') {
            return dateA.month === dateB.month ? 0 : -1;
        } else if (this.groupByMode === "Year") {
            return dateA.year === dateB.year ? 0 : -1;
        } else if (this.groupByMode === "Week") {
            return this.sortingStrategy.getWeekOfDate(a) === this.sortingStrategy.getWeekOfDate(b) ? 0 : -1;
        }
        return dateA.day === dateB.day && dateA.month === dateB.month ? 0 : -1;
    }
    

    A partir da versão 15.1.0, você também pode usar a estratégiaGroupMemberCountSortingStrategy de ordenação embutida para ordenar itens com base na contagem de membros.

    public sortByGroup() {
            const expressions = this.grid1.groupingExpressions;
            if (expressions.length) {
                const fieldName = expressions[0].fieldName;
                const dir = expressions[0].dir === SortingDirection.Asc ? SortingDirection.Desc : SortingDirection.Asc;
                this.grid1.groupBy({ fieldName, dir, ignoreCase: false, strategy: GroupMemberCountSortingStrategy.instance() });
            }
        }
    

    Estilização

    O igxGrid permite estilização através doIgnite UI for Angular Theme Library. A gradegrid-theme expõe uma grande variedade de propriedades, que permitem a personalização de todos os recursos da grade.

    Nas etapas abaixo, estamos passando pelas etapas de personalização do estilo Agrupar por da grade.

    Importing global theme

    Para começar a customização do recurso Group By, você precisa importar oindex arquivo, onde todas as funções de estilo e mixins estão localizadas.

    @use "igniteui-angular/theming" as *;
    
    // IMPORTANT: Prior to Ignite UI for Angular version 13 use:
    // @import '~igniteui-angular/lib/core/styles/themes/index';
    

    Defining custom theme

    Em seguida, crie um novo tema, que estenda ogrid-theme e aceite os parâmetros necessários para personalizar o Grupo By conforme desejado. Você também precisa estender o jogochip-theme, porque ele é usado no recurso Agrupar Por.

    
    $custom-theme: grid-theme(
      $group-row-background: #494949,
      $group-row-selected-background: #383838,
      $group-label-column-name-text: #f8f8f8,
      $group-label-icon: #ffcd0f,
      $group-label-text: #f8f8f8,
      $group-count-background: #ffcd0f,
      $group-count-text-color: #000,
      $expand-icon-color: #ffcd0f,
      $expand-icon-hover-color: rgb(223, 181, 13),
      $cell-active-border-color: #ffcd0f,
      $row-selected-background: #fff6d3,
      $row-selected-text-color: #000,
      $drop-indicator-color: #ffcd0f
    );
    
    /* Chip theme will style the chips in the Group By area */
    $custom-chips-theme: chip-theme(
      $background: #494949,
      $text-color: #f8f8f8,
      $hover-text-color: #e7e7e7
    );
    

    Defining a custom color palette

    Na abordagem que descrevemos acima, os valores de cor eram codificados fixamente. Alternativamente, você pode alcançar maior flexibilidade, usando opalette ecolor Funções.palette Gera uma paleta de cores, baseada nas cores primárias, secundárias e de superfície fornecidas.

    $black-color: #292826;
    $yellow-color: #ffcd0f;
    $grey-color: #efefef;
    
    $custom-palette: palette(
      $primary: $black-color, 
      $secondary: $yellow-color, 
      $surface: $grey-color
    );
    

    Após a geração de uma paleta personalizada, acolor função pode ser usada para obter diferentes variedades das cores primária e secundária.

    $custom-theme: grid-theme(
      $group-row-background: color($custom-palette, "primary", 300),
      $group-row-selected-background: color($custom-palette, "primary", 400),
      $group-label-column-name-text:contrast-color($custom-palette, "primary", 500),
      $group-label-icon: color($custom-palette, "secondary", 600),
      $group-label-text:contrast-color($custom-palette, "primary", 500),
      $group-count-background: color($custom-palette, "secondary", 600),
      $group-count-text-color: color($custom-palette, "primary", 400),
      $expand-icon-color: color($custom-palette, "secondary", 600),
      $expand-icon-hover-color: color($custom-palette, "secondary", 300),
      $cell-active-border-color: color($custom-palette, "secondary", 600)
    );
    
    $custom-chips-theme: chip-theme(
      $background: color($custom-palette, "primary", 300),
      $text-color:contrast-color($custom-palette, "primary", 500),
      $hover-text-color:contrast-color($custom-palette, "primary", 600)
    );
    

    Defining custom schemas

    Você pode ir ainda mais longe e construir uma estrutura flexível que tenha todos os benefícios de um esquema. O esquema é a receita de um tema. Estenda um dos dois esquemas predefinidos que são fornecidos para cada componente. No nosso caso, usaríamoslight-grid.

    $custom-grid-schema: extend(
      map.get('grid', $light-material-schema),
      (
        group-row-background: (color:('secondary', 100)),
        group-row-selected-background: (color:('primary', 400)),
        group-label-column-name-text: (color:('primary', 600)),
        group-label-icon: (color:('primary', 600)),
        group-label-text: (color:('secondary', 700)),
        group-count-background: (color:('primary', 600)),
        group-count-text-color: (color:('secondary', 400)),
        expand-icon-color: (color:('primary', 600)),
        expand-icon-hover-color: (color:('primary', 400))
      )
    );
    

    Para que o esquema personalizado seja aplicado, qualquerlightdark um dos globais precisa ser estendido. Todo o processo é, na verdade, fornecer um esquema personalizado a um componente e adicioná-lo ao tema do componente respectivo em seguida.

    $my-custom-schema: extend(
      $light-material-schema, 
      ( 
        grid: $custom-grid-schema
      )
    );
    
    $custom-theme: grid-theme(
      $palette: $custom-palette,
      $schema: $my-custom-schema
    );
    

    Applying the custom theme

    A maneira mais fácil de aplicar seu tema é com umasass @include instrução no arquivo de estilos globais:

    @include css-vars($custom-theme);
    @include css-vars($custom-chips-theme);
    

    Scoped component theme

    Para que o tema personalizado afete apenas um componente específico, você pode mover todos os estilos que acabou de definir do arquivo de estilos globais para o arquivo de estilo do componente personalizado (incluindo a importação doindex arquivo).

    Dessa forma, devido ao ViewEncapsulation do Angular, seus estilos serão aplicados somente ao seu componente personalizado.

    Note

    Se o componente estiver usando umEmulated ViewEncapsulation, é necessário penetrar esse encapsulamento para::ng-deep estilizar os componentes que estão dentro da grade.

    No nosso exemplo, precisamos usar::ng-deep para o tema do chip:

    @include css-vars($custom-theme);
    
    :host {
      ::ng-deep {
        @include chip($custom-chips-theme);
      }
    }
    

    Demo

    Note

    A amostra não será afetada pelo tema global selecionado deChange Theme.

    Known Limitations

    Limitação Descrição
    A quantidade máxima de colunas agrupadas é 10. Se mais de 10 colunas forem agrupadas, um erro será gerado.

    API References

    Additional Resources

    Nossa comunidade é ativa e sempre acolhedora para novas ideias.