Skip to content

Commit

Permalink
feat: group selection no longer affects disabled items (#1434) (#1437)
Browse files Browse the repository at this point in the history
  • Loading branch information
NicolasPennie authored and varnastadeus committed Dec 2, 2019
1 parent 87908d3 commit 4416422
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 7 deletions.
Expand Up @@ -20,7 +20,7 @@ export class GroupSelectableExampleComponent implements OnInit {
{ name: 'Estefanía', email: 'estefania@email.com', age: 21, country: 'Argentina', child: { state: 'Active' } },
{ name: 'Adrian', email: 'adrian@email.com', age: 21, country: 'Ecuador', child: { state: 'Active' } },
{ name: 'Wladimir', email: 'wladimir@email.com', age: 30, country: 'Ecuador', child: { state: 'Inactive' } },
{ name: 'Natasha', email: 'natasha@email.com', age: 54, country: 'Ecuador', child: { state: 'Inactive' } },
{ name: 'Natasha', email: 'natasha@email.com', age: 54, country: 'Ecuador', child: { state: 'Inactive' }, disabled: true },
{ name: 'Nicole', email: 'nicole@email.com', age: 43, country: 'Colombia', child: { state: 'Inactive' } },
{ name: 'Michael', email: 'michael@email.com', age: 15, country: 'Colombia', child: { state: 'Inactive' } },
{ name: 'Nicolás', email: 'nicole@email.com', age: 43, country: 'Colombia', child: { state: 'Inactive' } }
Expand Down
90 changes: 90 additions & 0 deletions src/ng-select/lib/items-list.spec.ts
Expand Up @@ -79,6 +79,33 @@ describe('ItemsList', () => {
expect(list.selectedItems.length).toBe(2);
});


it('should not select disabled items when selecting group', () => {
cmp.groupBy = 'groupKey';
list.setItems([
{ label: 'K1', val: 'V1', groupKey: 'G1' },
{ label: 'K2', val: 'V2', groupKey: 'G1', disabled: true }
]);
list.select(list.items[0]); // G1

expect(list.selectedItems.length).toBe(1);
expect(list.selectedItems[0].label).toBe('K1');
});

it('should select group when disabled items are selected', () => {
cmp.groupBy = 'groupKey';
list.setItems([
{ label: 'K1', val: 'V1', groupKey: 'G1' },
{ label: 'K2', val: 'V2', groupKey: 'G1', disabled: true }
]);
list.select(list.items[2]) // K2
list.select(list.items[0]); // G1

expect(list.selectedItems.length).toBe(1);
expect(list.selectedItems[0].label).toBe('G1');
});


it('should remove item from filtered items when hideSelected=true', () => {
cmp.hideSelected = true;
list.setItems([
Expand Down Expand Up @@ -148,6 +175,8 @@ describe('ItemsList', () => {
list.setItems([
{ label: 'K1', val: 'V1', groupKey: 'G1' },
{ label: 'K2', val: 'V2', groupKey: 'G1' },
{ label: 'K3', val: 'V3', groupKey: 'G2'},
{ label: 'K4', val: 'V4', groupKey: 'G2', disabled: true},
]);
});

Expand All @@ -165,6 +194,12 @@ describe('ItemsList', () => {
expect(list.selectedItems[0].label).toBe('K1');
expect(list.selectedItems[1].label).toBe('K2');
});

it('should not select disabled items', () => {
list.select(list.items[3]); // G2
expect(list.selectedItems.length).toBe(1);
expect(list.selectedItems[0].label).toBe('K3');
});
})
});
});
Expand Down Expand Up @@ -243,6 +278,61 @@ describe('ItemsList', () => {
expect(list.selectedItems[0].label).toBe(list.items[2].label); // should select only K2
});

it('should not unselect disabled items within a group', () => {
cmp.groupBy = 'groupKey';
list.setItems([
{ label: 'K1', val: 'V1', groupKey: 'G1' },
{ label: 'K2', val: 'V2', groupKey: 'G1', disabled: true },
{ label: 'K3', val: 'V3', groupKey: 'G2' },
{ label: 'K4', val: 'V4', groupKey: 'G2', disabled: true },
]);

list.select(list.findByLabel('K2'));
list.select(list.findByLabel('K4'));
list.select(list.findByLabel('G1'));
list.select(list.findByLabel('G2'));
expect(list.selectedItems.length).toBe(2);
expect(list.selectedItems[0].label).toBe('G1');
expect(list.selectedItems[1].label).toBe('G2');

list.unselect(list.findByLabel('G1'));
expect(list.selectedItems.length).toBe(2);
expect(list.selectedItems[0].label).toBe('G2');
});

it('should not unselect disabled items within a group (groupAsModel=false)', () => {
cmp.groupBy = 'groupKey';
cmp.selectableGroupAsModel = false;
list.setItems([
{ label: 'K1', val: 'V1', groupKey: 'G1' },
{ label: 'K2', val: 'V2', groupKey: 'G1', disabled: true },
]);

list.select(list.items[2]); // K2
list.select(list.items[0]); // G1
expect(list.selectedItems.length).toBe(2);
expect(list.selectedItems.find(x => x.label === 'K1')).toBeDefined();
expect(list.selectedItems.find(x => x.label === 'K2')).toBeDefined();

list.unselect(list.items[0]); // G1
expect(list.selectedItems.length).toBe(1);
expect(list.selectedItems[0].label).toBe('K2');
});

it('should not affect disabled items when un-selecting a group', () => {
cmp.groupBy = 'groupKey';
list.setItems([
{ label: 'K1', val: 'V1', groupKey: 'G1' },
{ label: 'K2', val: 'V2', groupKey: 'G1' },
{ label: 'K3', val: 'V3', groupKey: 'G1', disabled: true },
]);

list.select(list.items[0]); // G1
list.unselect(list.items[1]); // K1
expect(list.selectedItems.length).toBe(1);
expect(list.selectedItems[0].label).toBe('K2');
});

it('should un-select selected item and insert it back to filtered items list when hideSelected=true', () => {
cmp.hideSelected = true;
list.setItems([
Expand Down
26 changes: 20 additions & 6 deletions src/ng-select/lib/selection-model.ts
Expand Up @@ -22,7 +22,7 @@ export class DefaultSelectionModel implements SelectionModel {

select(item: NgOption, multiple: boolean, groupAsModel: boolean) {
item.selected = true;
if (groupAsModel || !item.children) {
if (!item.children || (!multiple && groupAsModel)) {
this._selected.push(item);
}
if (multiple) {
Expand All @@ -33,8 +33,10 @@ export class DefaultSelectionModel implements SelectionModel {
} else if (item.children) {
this._setChildrenSelectedState(item.children, true);
this._removeChildren(item);
if (!groupAsModel) {
this._selected = [...this._selected, ...item.children];
if (groupAsModel && this._activeChildren(item)) {
this._selected = [...this._selected.filter(x => x.parent !== item), item]
} else {
this._selected = [...this._selected, ...item.children.filter(x => !x.disabled)];
}
}
}
Expand All @@ -48,7 +50,7 @@ export class DefaultSelectionModel implements SelectionModel {
const children = item.parent.children;
this._removeParent(item.parent);
this._removeChildren(item.parent);
this._selected.push(...children.filter(x => x !== item));
this._selected.push(...children.filter(x => x !== item && !x.disabled));
item.parent.selected = false;
} else if (item.children) {
this._setChildrenSelectedState(item.children, false);
Expand All @@ -62,14 +64,26 @@ export class DefaultSelectionModel implements SelectionModel {
}

private _setChildrenSelectedState(children: NgOption[], selected: boolean) {
children.forEach(x => x.selected = selected);
for (const child of children) {
if (child.disabled) {
continue;
}
child.selected = selected;
};
}

private _removeChildren(parent: NgOption) {
this._selected = this._selected.filter(x => x.parent !== parent);
this._selected = [
...this._selected.filter(x => x.parent !== parent),
...parent.children.filter(x => x.parent === parent && x.disabled && x.selected)
];
}

private _removeParent(parent: NgOption) {
this._selected = this._selected.filter(x => x !== parent)
}

private _activeChildren(item: NgOption): boolean {
return item.children.every(x => !x.disabled || x.selected);
}
}

0 comments on commit 4416422

Please sign in to comment.