Skip to content

Commit

Permalink
fix(table): aplica regra indeterminate no checkbox
Browse files Browse the repository at this point in the history
Aplica o indeterminate no registro 'pai' e no 'selecionar todos' quando um registro "filho" for selecionado.

fixes DTHFUI-7346
  • Loading branch information
jnrpalma authored and anderson-gregorio-totvs committed Oct 21, 2024
1 parent 09a1a80 commit 1ec244f
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,46 @@ describe('PoTableBaseComponent:', () => {
expect(component['emitSelectEvents']).toHaveBeenCalledWith(row);
});

it('selectRow: should update child items $selected property if row has detail', () => {
const childItems = [
{ id: 2, $selected: false },
{ id: 3, $selected: false }
];
const row = { id: 1, $selected: false, detail: childItems };

component.selectRow(row);

expect(row.$selected).toBeTruthy();
row.detail.forEach(childItem => {
expect(childItem.$selected).toBeTruthy();
});
});

it('selectRow: should call setSelectedList after selecting a row', () => {
const row = { id: 1, $selected: false };

spyOn(component, 'setSelectedList');

component.selectRow(row);

expect(component.setSelectedList).toHaveBeenCalled();
});

it('selectRow: should update child items $selected property if row has detail and $selected is false', () => {
const childItems = [
{ id: 2, $selected: true },
{ id: 3, $selected: true }
];
const row = { id: 1, $selected: true, detail: childItems };

component.selectRow(row);

expect(row.$selected).toBeFalsy();
row.detail.forEach(childItem => {
expect(childItem.$selected).toBeFalsy();
});
});

it('emitSelectEvents: should emit `selected` if `row.$selected` is `true`', () => {
const row = { id: 1, $selected: true };
spyOn(component.selected, 'emit');
Expand Down Expand Up @@ -787,6 +827,80 @@ describe('PoTableBaseComponent:', () => {
expect(component['emitSelectAllEvents']).toHaveBeenCalled();
});

describe('selectAllRows:', () => {
beforeEach(() => {
component.hideSelectAll = false;
component.selectAll = false;
component.items = [
{ id: 1, $selected: false, detail: [{ id: 4, $selected: false }] },
{ id: 2, $selected: false, detail: [{ id: 5, $selected: false }] }
];
});

it('should call emitSelectEvents and updateParentRowSelection', () => {
const row = { id: 1, $selected: false, detail: [{ id: 4 }] };
const parentRow = { id: 2, detail: [row] };

spyOn(component, <any>'emitSelectEvents');
spyOn(component, <any>'updateParentRowSelection');

component.selectDetailRow({ item: row, parentRow });

expect(component['emitSelectEvents']).toHaveBeenCalledWith(row);
expect(component['updateParentRowSelection']).toHaveBeenCalledWith(parentRow);
});

it('should select all rows when selectAll is false', () => {
component.selectAllRows();

expect(component.selectAll).toBeTrue();
component.items.forEach(item => {
expect(item.$selected).toBeTrue();
item.detail.forEach(childItem => {
expect(childItem.$selected).toBeTrue();
});
});
});

it('should unselect all rows when selectAll is true', () => {
component.selectAll = true;
component.items.forEach(item => {
item.$selected = true;
item.detail.forEach(childItem => (childItem.$selected = true));
});

component.selectAllRows();

expect(component.selectAll).toBeFalse();
component.items.forEach(item => {
expect(item.$selected).toBeFalse();
item.detail.forEach(childItem => {
expect(childItem.$selected).toBeFalse();
});
});
});

it('should not select all rows if hideSelectAll is true', () => {
component.hideSelectAll = true;

component.selectAllRows();

component.items.forEach(item => {
expect(item.$selected).toBeFalse();
});
});

it('should emit selectAll events and update selected list', () => {
spyOn(component as any, 'emitSelectAllEvents');
spyOn(component, 'setSelectedList');

component.selectAllRows();

expect((component as any).emitSelectAllEvents).toHaveBeenCalledWith(true, jasmine.any(Array));
expect(component.setSelectedList).toHaveBeenCalled();
});
});

it('emitSelectAllEvents: should emit `allSelected` if `selectAll` is `true`', () => {
const rows = [{ id: 1, $selected: true }];
const selectAll = true;
Expand All @@ -809,14 +923,34 @@ describe('PoTableBaseComponent:', () => {
expect(component.allUnselected.emit).toHaveBeenCalledWith(rows);
});

it('selectDetailRow: should call `emitSelectEvents`', () => {
const row = { id: 1, $selected: false };
it('updateParentRowSelection: should set parentRow.$selected to true if all child items are selected', () => {
const parentRow: any = {
detail: [{ $selected: true }, { $selected: true }, { $selected: true }]
};

spyOn(component, <any>'emitSelectEvents');
component.updateParentRowSelection(parentRow);

component.selectDetailRow(row);
expect(parentRow.$selected).toBe(true);
});

expect(component['emitSelectEvents']).toHaveBeenCalledWith(row);
it('updateParentRowSelection: should set parentRow.$selected to false if all child items are not selected', () => {
const parentRow: any = {
detail: [{ $selected: false }, { $selected: false }, { $selected: false }]
};

component.updateParentRowSelection(parentRow);

expect(parentRow.$selected).toBe(false);
});

it('updateParentRowSelection: should set parentRow.$selected to null if some child items are selected and some are not', () => {
const parentRow: any = {
detail: [{ $selected: true }, { $selected: false }, { $selected: true }]
};

component.updateParentRowSelection(parentRow);

expect(parentRow.$selected).toBeNull();
});

describe('getColumnColor:', () => {
Expand Down
37 changes: 34 additions & 3 deletions projects/ui/src/lib/components/po-table/po-table-base.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1024,6 +1024,11 @@ export abstract class PoTableBaseComponent implements OnChanges, OnDestroy {

this.items.forEach(item => {
item.$selected = this.selectAll;

if (item[this.nameColumnDetail]) {
const childItems = item[this.nameColumnDetail];
childItems.forEach(childItem => (childItem.$selected = this.selectAll));
}
});

this.emitSelectAllEvents(this.selectAll, [...this.items]);
Expand All @@ -1035,17 +1040,43 @@ export abstract class PoTableBaseComponent implements OnChanges, OnDestroy {
row.$selected = !row.$selected;

this.emitSelectEvents(row);

this.configAfterSelectRow(this.items, row);

if (row[this.nameColumnDetail] && (row.$selected === true || row.$selected === false)) {
const childItems = row[this.nameColumnDetail];
childItems.forEach(item => (item.$selected = row.$selected));
}

this.setSelectedList();
}

hasSelectableRow(): boolean {
return this.selectable && this.selectableEntireLine;
}

selectDetailRow(row: any) {
this.emitSelectEvents(row);
selectDetailRow(event: any) {
const { item, parentRow } = event;
this.emitSelectEvents(item);
this.updateParentRowSelection(parentRow);
}

updateParentRowSelection(parentRow: any) {
const old = parentRow.$selected || null;
const childItems = parentRow[this.nameColumnDetail];

if (childItems.every(item => item.$selected)) {
parentRow.$selected = true;
} else if (childItems.every(item => !item.$selected)) {
parentRow.$selected = false;
} else {
parentRow.$selected = null;
}
if (old != parentRow.$selected && !(old == null && parentRow.$selected === false)) {
this.emitSelectEvents(parentRow);
}

this.configAfterSelectRow(this.items, parentRow);
this.setSelectedList();
}

setSelectedList() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,7 @@
<ng-container *ngIf="isSelectable; else masterDetailSpace">
<td class="po-table-column-master-detail-space-checkbox"></td>
<td class="po-table-column po-table-column-selectable">
<po-checkbox
name="checkbox"
(click)="onSelectRow(item)"
(p-change)="onSelectRow(item)"
[(ngModel)]="item.$selected"
></po-checkbox>
<po-checkbox name="checkbox" (p-change)="onSelectRow(item)" [p-checkboxValue]="item.$selected"></po-checkbox>
</td>
</ng-container>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ describe('PoTableDetailComponent', () => {
component.onSelectRow(row);

expect(row.$selected).toBeTruthy();
expect(component.selectRow.emit).toHaveBeenCalledWith(row);
expect(component.selectRow.emit).toHaveBeenCalledWith({ item: row, parentRow: undefined });
});

describe('returnPoTableDetailObject: ', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ export class PoTableDetailComponent {
*/
@Input('p-items') items: Array<any>;

/**
* Linha do registro pai correspondente ao item de detalhe selecionado. Utilizado para gerenciar o estado de seleção do elemento pai,
* permitindo que o mesmo seja atualizado para refletir a seleção de todos os filhos ou estado indeterminado.
*/
@Input('p-parent-row') parentRow: PoTableDetail;

/**
* Define se a tabela possui a opção de `selectable` habilitada.
*/
Expand Down Expand Up @@ -92,7 +98,7 @@ export class PoTableDetailComponent {

onSelectRow(item) {
item.$selected = !item.$selected;
this.selectRow.emit(item);
this.selectRow.emit({ item: item, parentRow: this.parentRow });
}

private returnPoTableDetailObject(value: any) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@
[p-selectable]="selectable && !detailHideSelect"
[p-detail]="columnMasterDetail.detail"
[p-items]="row[nameColumnDetail]"
[p-parent-row]="row"
(p-select-row)="selectDetailRow($event)"
>
</po-table-detail>
Expand Down Expand Up @@ -790,6 +791,7 @@
[p-selectable]="selectable && !detailHideSelect"
[p-detail]="columnMasterDetail.detail"
[p-items]="row[nameColumnDetail]"
[p-parent-row]="row"
(p-select-row)="selectDetailRow($event)"
>
</po-table-detail>
Expand Down Expand Up @@ -820,7 +822,7 @@
<po-checkbox
name="checkbox"
(p-change)="selectable ? selectRow(row) : 'javascript:;'"
[p-checkboxValue]="row.$selected"
[p-checkboxValue]="row.$selected === null ? 'mixed' : row.$selected"
></po-checkbox>
</ng-template>

Expand Down

0 comments on commit 1ec244f

Please sign in to comment.