From 27c03b22f4fc26d8de3a8b3f168ae9f5eda29b72 Mon Sep 17 00:00:00 2001 From: Vishal Shah Date: Mon, 22 May 2023 11:39:59 +0530 Subject: [PATCH 01/20] bug fixes for select all filtered list --- .../go-select/go-select.component.html | 13 +- .../go-select/go-select.component.ts | 115 ++++++++++++++++-- 2 files changed, 110 insertions(+), 18 deletions(-) diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.html b/projects/go-lib/src/lib/components/go-select/go-select.component.html index 355136a30..1d018ec98 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.html +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.html @@ -6,7 +6,6 @@ {{ label }} - - + @@ -78,4 +81,4 @@ [theme]="theme"> - \ No newline at end of file + diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.ts b/projects/go-lib/src/lib/components/go-select/go-select.component.ts index 9cb67b68a..a5814adcb 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.ts +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.ts @@ -1,14 +1,30 @@ -import { Component, ContentChild, EventEmitter, Input, OnInit, Output, TemplateRef, ViewEncapsulation } from '@angular/core'; -import { Subject } from 'rxjs'; -import { GoFormBaseComponent } from '../go-form-base/go-form-base.component'; +import { + Component, + ContentChild, + EventEmitter, + Input, + OnDestroy, + OnInit, + Output, + TemplateRef, + ViewChild, + ViewEncapsulation, +} from "@angular/core"; +import { Subject, Subscription } from "rxjs"; +import { GoFormBaseComponent } from "../go-form-base/go-form-base.component"; +import { NgSelectComponent } from "@ng-select/ng-select"; @Component({ encapsulation: ViewEncapsulation.None, - selector: 'go-select', - templateUrl: './go-select.component.html', - styleUrls: ['./go-select.component.scss'] + selector: "go-select", + templateUrl: "./go-select.component.html", + styleUrls: ["./go-select.component.scss"], }) -export class GoSelectComponent extends GoFormBaseComponent implements OnInit { +export class GoSelectComponent + extends GoFormBaseComponent + implements OnInit, OnDestroy +{ + @ViewChild(NgSelectComponent) ngSelect: NgSelectComponent; @Input() appendTo: string; @Input() bindLabel: string; @@ -30,26 +46,84 @@ export class GoSelectComponent extends GoFormBaseComponent implements OnInit { @Input() searchable: boolean = true; @Input() showSelectAll: boolean = true; @Input() typeahead?: Subject; - @Input() typeToSearchText: string = 'Type to Search'; + @Input() typeToSearchText: string = "Type to Search"; @Input() virtualScroll: boolean = false; @Output() scrollToEnd: EventEmitter = new EventEmitter(); - @Output() scroll: EventEmitter<{ start: number, end: number }> = new EventEmitter<{ start: number; end: number }>(); + @Output() scroll: EventEmitter<{ start: number; end: number }> = + new EventEmitter<{ start: number; end: number }>(); - @ContentChild('goSelectOption') goSelectOption: TemplateRef; - @ContentChild('goSelectOptionGroup') goSelectOptionGroup: TemplateRef; - @ContentChild('goSelectSelectedOption') goSelectSelectedOption: TemplateRef; + @ContentChild("goSelectOption") goSelectOption: TemplateRef; + @ContentChild("goSelectOptionGroup") goSelectOptionGroup: TemplateRef; + @ContentChild("goSelectSelectedOption") + goSelectSelectedOption: TemplateRef; + + private controlSubscription: Subscription; + // store refined items after search + private refinedItems: any[] = []; + // stores previous selected items when typeahead is enabled only in case of selectAll. + private previousSelectedItems: any[] = []; ngOnInit(): void { this.closeOnSelect = this.multiple ? false : this.closeOnSelect; + this.controlSubscription = this.control.valueChanges.subscribe((value) => { + if (this.multiple && this.showSelectAll) { + this.emptyRefinedItems(); + if (!value?.length) { + this.resetTypeaheadItems(); + } + } + }); + } + + ngOnDestroy(): void { + this.controlSubscription.unsubscribe(); } onSelectAll(): void { - this.control.patchValue(this.items.map((item: any) => this.bindValue ? item[this.bindValue] : item)); + if (this.typeahead) { + this.handleTypeaheadSelectAll(); + return; + } + const items = this.refinedItems.length ? this.refinedItems : this.items; + this.processSelectAll(items); + } + + private processSelectAll(items: any[]) { + const refinedArr = items.map((item: any) => + this.bindValue ? item[this.bindValue] : item + ); + const existing = Array.isArray(this.control.value) ? this.control.value : []; + this.control.patchValue(existing.concat(refinedArr)); + this.ngSelect.searchTerm = ""; + this.ngSelect.itemsList.resetFilteredItems(); + } + + private handleTypeaheadSelectAll() { + // because spread operator is not supported due to tslib version + const items = JSON.parse(JSON.stringify(this.items)); + for (let previousItem of this.previousSelectedItems) { + const exists = items.find( + (item) => item[this.bindValue] === previousItem[this.bindValue] + ); + if (!exists) { + items.unshift(previousItem); + } + } + + this.previousSelectedItems = items; + this.items = items; + this.control.reset([], { emitEvent: false }); + this.processSelectAll(items); + } + + handleInput(search: { term: string; items: any[] }) { + this.refinedItems = search.items; } onRemoveAll(): void { this.control.reset(); + this.resetTypeaheadItems(); } onScrollToEnd(): void { @@ -61,4 +135,19 @@ export class GoSelectComponent extends GoFormBaseComponent implements OnInit { onScroll($event: { start: number; end: number }): void { this.scroll.emit($event); } + + private resetTypeaheadItems() { + if (this.typeahead) { + this.items = []; + this.previousSelectedItems = []; + } + } + + private emptyRefinedItems(): void { + this.refinedItems = []; + } + + onClose() { + this.emptyRefinedItems(); + } } From 6a976b01c5fe7f5b689a44ef59dc05c02b8e98b7 Mon Sep 17 00:00:00 2001 From: vishal-tangoe Date: Mon, 22 May 2023 12:36:12 +0530 Subject: [PATCH 02/20] single item, add remove handled --- .../go-select/go-select.component.html | 3 +++ .../components/go-select/go-select.component.ts | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.html b/projects/go-lib/src/lib/components/go-select/go-select.component.html index 1d018ec98..f6f9a64ad 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.html +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.html @@ -9,6 +9,8 @@ this.bindValue ? item[this.bindValue] : item ); + + const existing = Array.isArray(this.control.value) ? this.control.value : []; this.control.patchValue(existing.concat(refinedArr)); this.ngSelect.searchTerm = ""; @@ -150,4 +152,18 @@ export class GoSelectComponent onClose() { this.emptyRefinedItems(); } + + // store previous selected items incase of multiple and typeahead. + handleItemAdd(item) { + if(!this.multiple || !this.typeahead) return; + this.previousSelectedItems.push(item) + } + + // remove item from previous selected items incase of multiple and typeahead. + handleItemRemove(item) { + if(!this.multiple || !this.typeahead) return; + const index = this.previousSelectedItems.findIndex(prev => prev[this.bindValue] === item.value[this.bindValue]); + this.previousSelectedItems.splice(index, 1) + } + } From 77c277b7ed1ce4afce798f803fc483b9256e9404 Mon Sep 17 00:00:00 2001 From: vishal-tangoe Date: Mon, 22 May 2023 16:50:54 +0530 Subject: [PATCH 03/20] handling controls initial value incase of typeahead provided --- .../go-select/go-select.component.spec.ts | 164 ++++++++++++++---- .../go-select/go-select.component.ts | 32 ++-- 2 files changed, 153 insertions(+), 43 deletions(-) diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts b/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts index 0192a663c..890076040 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts @@ -1,14 +1,15 @@ -import { CommonModule } from '@angular/common'; -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { NgSelectModule } from '@ng-select/ng-select'; -import { GoButtonModule } from '../go-button/go-button.module'; -import { GoFormErrorsModule } from '../go-form-errors/go-form-errors.module'; -import { GoHintModule } from '../go-hint/go-hint.module'; -import { GoRequiredTextModule } from '../go-required-text/go-required-text.module'; -import { GoSelectComponent } from './go-select.component'; - -describe('GoSelectComponent', () => { +import { CommonModule } from "@angular/common"; +import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { FormControl, FormsModule, ReactiveFormsModule } from "@angular/forms"; +import { NgSelectModule } from "@ng-select/ng-select"; +import { GoButtonModule } from "../go-button/go-button.module"; +import { GoFormErrorsModule } from "../go-form-errors/go-form-errors.module"; +import { GoHintModule } from "../go-hint/go-hint.module"; +import { GoRequiredTextModule } from "../go-required-text/go-required-text.module"; +import { GoSelectComponent } from "./go-select.component"; +import { Subject } from "rxjs"; + +describe("GoSelectComponent", () => { let component: GoSelectComponent; let fixture: ComponentFixture; @@ -23,30 +24,29 @@ describe('GoSelectComponent', () => { GoRequiredTextModule, NgSelectModule, FormsModule, - ReactiveFormsModule - ] - }) - .compileComponents(); + ReactiveFormsModule, + ], + }).compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(GoSelectComponent); component = fixture.componentInstance; - component.control = new FormControl('Some Value'); + component.control = new FormControl("Some Value"); fixture.detectChanges(); }); - it('should create', () => { + it("should create", () => { expect(component).toBeTruthy(); }); - describe('onSelectAll()', () => { - it('adds all of the available items to the form control value', () => { + describe("onSelectAll()", () => { + it("adds all of the available items to the form control value", () => { component.bindValue = undefined; component.items = [ - { value: 1, label: 'Label 1' }, - { value: 2, label: 'Label 2' }, - { value: 3, label: 'Label 3' } + { value: 1, label: "Label 1" }, + { value: 2, label: "Label 2" }, + { value: 3, label: "Label 3" }, ]; component.onSelectAll(); @@ -54,27 +54,126 @@ describe('GoSelectComponent', () => { expect(component.control.value).toEqual(component.items); }); - it('uses bindValue to get value if bindValue exists', () => { - component.bindValue = 'id'; + it("uses bindValue to get value if bindValue exists", () => { + component.bindValue = "id"; component.items = [ - { id: 1, label: 'Label 1' }, - { id: 2, label: 'Label 2' }, - { id: 3, label: 'Label 3' } + { id: 1, label: "Label 1" }, + { id: 2, label: "Label 2" }, + { id: 3, label: "Label 3" }, ]; component.onSelectAll(); expect(component.control.value).toEqual([1, 2, 3]); }); + + it("should select only filtered list, when filtered and selectAll", () => { + component.bindValue = "id"; + component.items = [ + { id: 1, label: "banana" }, + { id: 2, label: "apple" }, + { id: 3, label: "green apple" }, + ]; + const filteredItems = [ + { id: 2, label: "apple" }, + { id: 3, label: "green apple" }, + ]; + component.handleInput({ items: filteredItems, term: "apple" }); + component.onSelectAll(); + expect(component.control.value).toEqual([2, 3]); + }); + + it("should select filtered list with existing items in control value, when filtered and selectAll", () => { + component.bindValue = "id"; + component.control.patchValue([4]); + component.items = [ + { id: 1, label: "banana" }, + { id: 2, label: "apple" }, + { id: 3, label: "green apple" }, + { id: 4, label: "grapes" }, + ]; + const filteredItems = [ + { id: 2, label: "apple" }, + { id: 3, label: "green apple" }, + ]; + component.handleInput({ items: filteredItems, term: "apple" }); + component.onSelectAll(); + expect(component.control.value).toEqual([4, 2, 3]); + }); + + it("should select filtered list with existing items in control value, when filtered and selectAll", () => { + component.bindValue = "id"; + component.control.patchValue([4]); + component.items = [ + { id: 1, label: "banana" }, + { id: 2, label: "apple" }, + { id: 3, label: "green apple" }, + { id: 4, label: "grapes" }, + ]; + const filteredItems = [ + { id: 2, label: "apple" }, + { id: 3, label: "green apple" }, + ]; + component.handleInput({ items: filteredItems, term: "apple" }); + component.onSelectAll(); + expect(component.control.value).toEqual([4, 2, 3]); + }); }); - describe('onRemoveAll', () => { - it('uses removed the selected values', () => { + describe("onSelectAll() with typeahead", () => { + beforeEach(() => { + component.typeahead = new Subject(); + component.multiple = true; + }); + + it("should store items in previousSelectedItems", () => { + const initialItems = [ + { id: 1, label: "banana" }, + { id: 2, label: "apple" }, + ]; + component.items = initialItems; + component["handleTypeaheadSelectAll"](); + expect(component["previousSelectedItems"]).toEqual(initialItems); + }); + + it("should add items in previousSelectedItems", () => { + component.handleItemAdd({ id: 1, label: "banana" }); + expect(component["previousSelectedItems"]).toEqual([ + { id: 1, label: "banana" }, + ]); + }); + + it("should remove items from previousSelectedItems", () => { + component["previousSelectedItems"] = [{ id: 1, label: "banana" }]; + component.handleItemRemove({ value: { id: 1, label: "banana" } }); + expect(component["previousSelectedItems"]).toEqual([]); + }); + }); + + describe("processSelectAll", () => { + it("process select all and patch value in form", () => { component.bindValue = 'id'; + const items = [ + { id: 1, label: "banana" }, + { id: 2, label: "apple" }, + { id: 3, label: "green apple" }, + { id: 4, label: "grapes" }, + ] + + component['processSelectAll'](items); + + expect(component.control.value).toEqual([1,2,3,4]) + }); + }); + + describe("onRemoveAll", () => { + it("uses removed the selected values", () => { + component.bindValue = "id"; + spyOn(component, "resetTypeaheadItems"); component.items = [ - { id: 1, label: 'Label 1' }, - { id: 2, label: 'Label 2' }, - { id: 3, label: 'Label 3' } + { id: 1, label: "Label 1" }, + { id: 2, label: "Label 2" }, + { id: 3, label: "Label 3" }, ]; component.onSelectAll(); @@ -82,6 +181,7 @@ describe('GoSelectComponent', () => { component.onRemoveAll(); expect(component.control.value).toBeNull(); + expect(component["resetTypeaheadItems"]).toHaveBeenCalled(); }); }); }); diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.ts b/projects/go-lib/src/lib/components/go-select/go-select.component.ts index eaf654004..0746032d1 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.ts +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.ts @@ -66,6 +66,7 @@ export class GoSelectComponent ngOnInit(): void { this.closeOnSelect = this.multiple ? false : this.closeOnSelect; + this.handleControlInitialValue(); this.controlSubscription = this.control.valueChanges.subscribe((value) => { if (this.multiple && this.showSelectAll) { this.emptyRefinedItems(); @@ -89,6 +90,14 @@ export class GoSelectComponent this.processSelectAll(items); } + private handleControlInitialValue() { + if(!this.typeahead && !Array.isArray(this.control.value)){ + return + } + this.previousSelectedItems = this.items; + + } + private processSelectAll(items: any[]) { const refinedArr = items.map((item: any) => this.bindValue ? item[this.bindValue] : item @@ -112,13 +121,23 @@ export class GoSelectComponent items.unshift(previousItem); } } - - this.previousSelectedItems = items; + this.previousSelectedItems = items this.items = items; this.control.reset([], { emitEvent: false }); this.processSelectAll(items); } + private resetTypeaheadItems() { + if (this.typeahead) { + this.items = []; + this.previousSelectedItems = []; + } + } + + private emptyRefinedItems(): void { + this.refinedItems = []; + } + handleInput(search: { term: string; items: any[] }) { this.refinedItems = search.items; } @@ -138,16 +157,7 @@ export class GoSelectComponent this.scroll.emit($event); } - private resetTypeaheadItems() { - if (this.typeahead) { - this.items = []; - this.previousSelectedItems = []; - } - } - private emptyRefinedItems(): void { - this.refinedItems = []; - } onClose() { this.emptyRefinedItems(); From e4fd3edcffacacf437da63616629ea420c03d072 Mon Sep 17 00:00:00 2001 From: vishal-tangoe Date: Mon, 22 May 2023 17:05:39 +0530 Subject: [PATCH 04/20] changes in handling controls initial value --- .../src/lib/components/go-select/go-select.component.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.ts b/projects/go-lib/src/lib/components/go-select/go-select.component.ts index 0746032d1..46e496254 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.ts +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.ts @@ -94,8 +94,14 @@ export class GoSelectComponent if(!this.typeahead && !Array.isArray(this.control.value)){ return } - this.previousSelectedItems = this.items; + const selected = this.control.value; + for(let value of selected) { + const exist = this.items.find(item => item[this.bindValue] === value); + if(exist) { + this.previousSelectedItems.push(exist) + } + } } private processSelectAll(items: any[]) { From 6960abc3534bb14181c526cdcf085c88d2a13021 Mon Sep 17 00:00:00 2001 From: vishal-tangoe Date: Mon, 22 May 2023 17:08:09 +0530 Subject: [PATCH 05/20] small condition fix --- .../go-lib/src/lib/components/go-select/go-select.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.ts b/projects/go-lib/src/lib/components/go-select/go-select.component.ts index 46e496254..44f848097 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.ts +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.ts @@ -91,7 +91,7 @@ export class GoSelectComponent } private handleControlInitialValue() { - if(!this.typeahead && !Array.isArray(this.control.value)){ + if(!this.typeahead || !Array.isArray(this.control.value)){ return } From 89097b427cf15585990004c83db0c86e8815d449 Mon Sep 17 00:00:00 2001 From: vishal-tangoe Date: Mon, 22 May 2023 17:56:37 +0530 Subject: [PATCH 06/20] test cases updated and condition change in init control value --- .../go-select/go-select.component.spec.ts | 33 +++++++++++++------ .../go-select/go-select.component.ts | 2 +- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts b/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts index 890076040..e0ea85994 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts @@ -1,5 +1,5 @@ import { CommonModule } from "@angular/common"; -import { async, ComponentFixture, TestBed } from "@angular/core/testing"; +import { async, ComponentFixture, fakeAsync, TestBed } from "@angular/core/testing"; import { FormControl, FormsModule, ReactiveFormsModule } from "@angular/forms"; import { NgSelectModule } from "@ng-select/ng-select"; import { GoButtonModule } from "../go-button/go-button.module"; @@ -148,21 +148,34 @@ describe("GoSelectComponent", () => { component.handleItemRemove({ value: { id: 1, label: "banana" } }); expect(component["previousSelectedItems"]).toEqual([]); }); + + it("handleControlInitialValue(), should assign previousSelectedItems", () => { + component.control.patchValue([1]); + component.bindValue = "id"; + component.items = [ + { id: 1, label: "banana" }, + { id: 2, label: "apple" }, + ]; + component["handleControlInitialValue"](); + expect(component["previousSelectedItems"]).toEqual([ + { id: 1, label: "banana" }, + ]); + }); }); describe("processSelectAll", () => { it("process select all and patch value in form", () => { - component.bindValue = 'id'; - const items = [ - { id: 1, label: "banana" }, - { id: 2, label: "apple" }, - { id: 3, label: "green apple" }, - { id: 4, label: "grapes" }, - ] + component.bindValue = "id"; + const items = [ + { id: 1, label: "banana" }, + { id: 2, label: "apple" }, + { id: 3, label: "green apple" }, + { id: 4, label: "grapes" }, + ]; - component['processSelectAll'](items); + component["processSelectAll"](items); - expect(component.control.value).toEqual([1,2,3,4]) + expect(component.control.value).toEqual([1, 2, 3, 4]); }); }); diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.ts b/projects/go-lib/src/lib/components/go-select/go-select.component.ts index 44f848097..71a158ab3 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.ts +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.ts @@ -91,7 +91,7 @@ export class GoSelectComponent } private handleControlInitialValue() { - if(!this.typeahead || !Array.isArray(this.control.value)){ + if((!this.typeahead && !this.multiple) || !Array.isArray(this.control.value)){ return } From f13eff35393800254c789bb9d50215eeedbe8402 Mon Sep 17 00:00:00 2001 From: vishal-tangoe Date: Tue, 23 May 2023 17:14:24 +0530 Subject: [PATCH 07/20] formatting changes --- .../go-select/go-select.component.html | 1 - .../go-select/go-select.component.spec.ts | 174 +++++++++--------- .../go-select/go-select.component.ts | 38 ++-- 3 files changed, 100 insertions(+), 113 deletions(-) diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.html b/projects/go-lib/src/lib/components/go-select/go-select.component.html index f6f9a64ad..c52e2857a 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.html +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.html @@ -34,7 +34,6 @@ [virtualScroll]="virtualScroll" (scrollToEnd)="onScrollToEnd()" (close)="onClose()" - (scroll)="onScroll($event)"> { +import { CommonModule } from '@angular/common'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { NgSelectModule } from '@ng-select/ng-select'; +import { GoButtonModule } from '../go-button/go-button.module'; +import { GoFormErrorsModule } from '../go-form-errors/go-form-errors.module'; +import { GoHintModule } from '../go-hint/go-hint.module'; +import { GoRequiredTextModule } from '../go-required-text/go-required-text.module'; +import { GoSelectComponent } from './go-select.component'; +import { Subject } from 'rxjs'; + +describe('GoSelectComponent', () => { let component: GoSelectComponent; let fixture: ComponentFixture; @@ -32,21 +32,21 @@ describe("GoSelectComponent", () => { beforeEach(() => { fixture = TestBed.createComponent(GoSelectComponent); component = fixture.componentInstance; - component.control = new FormControl("Some Value"); + component.control = new FormControl('Some Value'); fixture.detectChanges(); }); - it("should create", () => { + it('should create', () => { expect(component).toBeTruthy(); }); - describe("onSelectAll()", () => { - it("adds all of the available items to the form control value", () => { + describe('onSelectAll()', () => { + it('adds all of the available items to the form control value', () => { component.bindValue = undefined; component.items = [ - { value: 1, label: "Label 1" }, - { value: 2, label: "Label 2" }, - { value: 3, label: "Label 3" }, + { value: 1, label: 'Label 1' }, + { value: 2, label: 'Label 2' }, + { value: 3, label: 'Label 3' }, ]; component.onSelectAll(); @@ -54,12 +54,12 @@ describe("GoSelectComponent", () => { expect(component.control.value).toEqual(component.items); }); - it("uses bindValue to get value if bindValue exists", () => { - component.bindValue = "id"; + it('uses bindValue to get value if bindValue exists', () => { + component.bindValue = 'id'; component.items = [ - { id: 1, label: "Label 1" }, - { id: 2, label: "Label 2" }, - { id: 3, label: "Label 3" }, + { id: 1, label: 'Label 1' }, + { id: 2, label: 'Label 2' }, + { id: 3, label: 'Label 3' }, ]; component.onSelectAll(); @@ -67,126 +67,126 @@ describe("GoSelectComponent", () => { expect(component.control.value).toEqual([1, 2, 3]); }); - it("should select only filtered list, when filtered and selectAll", () => { - component.bindValue = "id"; + it('should select only filtered list, when filtered and selectAll', () => { + component.bindValue = 'id'; component.items = [ - { id: 1, label: "banana" }, - { id: 2, label: "apple" }, - { id: 3, label: "green apple" }, + { id: 1, label: 'banana' }, + { id: 2, label: 'apple' }, + { id: 3, label: 'green apple' }, ]; const filteredItems = [ - { id: 2, label: "apple" }, - { id: 3, label: "green apple" }, + { id: 2, label: 'apple' }, + { id: 3, label: 'green apple' }, ]; - component.handleInput({ items: filteredItems, term: "apple" }); + component.handleInput({ items: filteredItems, term: 'apple' }); component.onSelectAll(); expect(component.control.value).toEqual([2, 3]); }); - it("should select filtered list with existing items in control value, when filtered and selectAll", () => { - component.bindValue = "id"; + it('should select filtered list with existing items in control value, when filtered and selectAll', () => { + component.bindValue = 'id'; component.control.patchValue([4]); component.items = [ - { id: 1, label: "banana" }, - { id: 2, label: "apple" }, - { id: 3, label: "green apple" }, - { id: 4, label: "grapes" }, + { id: 1, label: 'banana' }, + { id: 2, label: 'apple' }, + { id: 3, label: 'green apple' }, + { id: 4, label: 'grapes' }, ]; const filteredItems = [ - { id: 2, label: "apple" }, - { id: 3, label: "green apple" }, + { id: 2, label: 'apple' }, + { id: 3, label: 'green apple' }, ]; - component.handleInput({ items: filteredItems, term: "apple" }); + component.handleInput({ items: filteredItems, term: 'apple' }); component.onSelectAll(); expect(component.control.value).toEqual([4, 2, 3]); }); - it("should select filtered list with existing items in control value, when filtered and selectAll", () => { - component.bindValue = "id"; + it('should select filtered list with existing items in control value, when filtered and selectAll', () => { + component.bindValue = 'id'; component.control.patchValue([4]); component.items = [ - { id: 1, label: "banana" }, - { id: 2, label: "apple" }, - { id: 3, label: "green apple" }, - { id: 4, label: "grapes" }, + { id: 1, label: 'banana' }, + { id: 2, label: 'apple' }, + { id: 3, label: 'green apple' }, + { id: 4, label: 'grapes' }, ]; const filteredItems = [ - { id: 2, label: "apple" }, - { id: 3, label: "green apple" }, + { id: 2, label: 'apple' }, + { id: 3, label: 'green apple' }, ]; - component.handleInput({ items: filteredItems, term: "apple" }); + component.handleInput({ items: filteredItems, term: 'apple' }); component.onSelectAll(); expect(component.control.value).toEqual([4, 2, 3]); }); }); - describe("onSelectAll() with typeahead", () => { + describe('onSelectAll() with typeahead', () => { beforeEach(() => { component.typeahead = new Subject(); component.multiple = true; }); - it("should store items in previousSelectedItems", () => { + it('should store items in previousSelectedItems', () => { const initialItems = [ - { id: 1, label: "banana" }, - { id: 2, label: "apple" }, + { id: 1, label: 'banana' }, + { id: 2, label: 'apple' }, ]; component.items = initialItems; - component["handleTypeaheadSelectAll"](); - expect(component["previousSelectedItems"]).toEqual(initialItems); + component['handleTypeaheadSelectAll'](); + expect(component['previousSelectedItems']).toEqual(initialItems); }); - it("should add items in previousSelectedItems", () => { - component.handleItemAdd({ id: 1, label: "banana" }); - expect(component["previousSelectedItems"]).toEqual([ - { id: 1, label: "banana" }, + it('should add items in previousSelectedItems', () => { + component.handleItemAdd({ id: 1, label: 'banana' }); + expect(component['previousSelectedItems']).toEqual([ + { id: 1, label: 'banana' }, ]); }); - it("should remove items from previousSelectedItems", () => { - component["previousSelectedItems"] = [{ id: 1, label: "banana" }]; - component.handleItemRemove({ value: { id: 1, label: "banana" } }); - expect(component["previousSelectedItems"]).toEqual([]); + it('should remove items from previousSelectedItems', () => { + component['previousSelectedItems'] = [{ id: 1, label: 'banana' }]; + component.handleItemRemove({ value: { id: 1, label: 'banana' } }); + expect(component['previousSelectedItems']).toEqual([]); }); - it("handleControlInitialValue(), should assign previousSelectedItems", () => { + it('handleControlInitialValue(), should assign previousSelectedItems', () => { component.control.patchValue([1]); - component.bindValue = "id"; + component.bindValue = 'id'; component.items = [ - { id: 1, label: "banana" }, - { id: 2, label: "apple" }, + { id: 1, label: 'banana' }, + { id: 2, label: 'apple' }, ]; - component["handleControlInitialValue"](); - expect(component["previousSelectedItems"]).toEqual([ - { id: 1, label: "banana" }, + component['handleControlInitialValue'](); + expect(component['previousSelectedItems']).toEqual([ + { id: 1, label: 'banana' }, ]); }); }); - describe("processSelectAll", () => { - it("process select all and patch value in form", () => { - component.bindValue = "id"; + describe('processSelectAll', () => { + it('process select all and patch value in form', () => { + component.bindValue = 'id'; const items = [ - { id: 1, label: "banana" }, - { id: 2, label: "apple" }, - { id: 3, label: "green apple" }, - { id: 4, label: "grapes" }, + { id: 1, label: 'banana' }, + { id: 2, label: 'apple' }, + { id: 3, label: 'green apple' }, + { id: 4, label: 'grapes' }, ]; - component["processSelectAll"](items); + component['processSelectAll'](items); expect(component.control.value).toEqual([1, 2, 3, 4]); }); }); - describe("onRemoveAll", () => { - it("uses removed the selected values", () => { - component.bindValue = "id"; - spyOn(component, "resetTypeaheadItems"); + describe('onRemoveAll', () => { + it('uses removed the selected values', () => { + component.bindValue = 'id'; + spyOn(component, 'resetTypeaheadItems'); component.items = [ - { id: 1, label: "Label 1" }, - { id: 2, label: "Label 2" }, - { id: 3, label: "Label 3" }, + { id: 1, label: 'Label 1' }, + { id: 2, label: 'Label 2' }, + { id: 3, label: 'Label 3' }, ]; component.onSelectAll(); @@ -194,7 +194,7 @@ describe("GoSelectComponent", () => { component.onRemoveAll(); expect(component.control.value).toBeNull(); - expect(component["resetTypeaheadItems"]).toHaveBeenCalled(); + expect(component['resetTypeaheadItems']).toHaveBeenCalled(); }); }); }); diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.ts b/projects/go-lib/src/lib/components/go-select/go-select.component.ts index 71a158ab3..c43e8494c 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.ts +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.ts @@ -1,24 +1,13 @@ -import { - Component, - ContentChild, - EventEmitter, - Input, - OnDestroy, - OnInit, - Output, - TemplateRef, - ViewChild, - ViewEncapsulation, -} from "@angular/core"; -import { Subject, Subscription } from "rxjs"; -import { GoFormBaseComponent } from "../go-form-base/go-form-base.component"; -import { NgSelectComponent } from "@ng-select/ng-select"; +import { Component, ContentChild, EventEmitter, Input, OnDestroy, OnInit, Output, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core'; +import { Subject, Subscription } from 'rxjs'; +import { GoFormBaseComponent } from '../go-form-base/go-form-base.component'; +import { NgSelectComponent } from '@ng-select/ng-select'; @Component({ encapsulation: ViewEncapsulation.None, - selector: "go-select", - templateUrl: "./go-select.component.html", - styleUrls: ["./go-select.component.scss"], + selector: 'go-select', + templateUrl: './go-select.component.html', + styleUrls: ['./go-select.component.scss'], }) export class GoSelectComponent extends GoFormBaseComponent @@ -46,16 +35,15 @@ export class GoSelectComponent @Input() searchable: boolean = true; @Input() showSelectAll: boolean = true; @Input() typeahead?: Subject; - @Input() typeToSearchText: string = "Type to Search"; + @Input() typeToSearchText: string = 'Type to Search'; @Input() virtualScroll: boolean = false; @Output() scrollToEnd: EventEmitter = new EventEmitter(); - @Output() scroll: EventEmitter<{ start: number; end: number }> = - new EventEmitter<{ start: number; end: number }>(); + @Output() scroll: EventEmitter<{ start: number; end: number }> = new EventEmitter<{ start: number; end: number }>(); - @ContentChild("goSelectOption") goSelectOption: TemplateRef; - @ContentChild("goSelectOptionGroup") goSelectOptionGroup: TemplateRef; - @ContentChild("goSelectSelectedOption") + @ContentChild('goSelectOption') goSelectOption: TemplateRef; + @ContentChild('goSelectOptionGroup') goSelectOptionGroup: TemplateRef; + @ContentChild('goSelectSelectedOption') goSelectSelectedOption: TemplateRef; private controlSubscription: Subscription; @@ -112,7 +100,7 @@ export class GoSelectComponent const existing = Array.isArray(this.control.value) ? this.control.value : []; this.control.patchValue(existing.concat(refinedArr)); - this.ngSelect.searchTerm = ""; + this.ngSelect.searchTerm = ''; this.ngSelect.itemsList.resetFilteredItems(); } From 7d91fb29f353b56a9dfd9f99e20d55fb11319e13 Mon Sep 17 00:00:00 2001 From: vishal-tangoe Date: Tue, 23 May 2023 17:44:50 +0530 Subject: [PATCH 08/20] formatting changes --- .../go-select/go-select.component.spec.ts | 16 ++++++++-------- .../components/go-select/go-select.component.ts | 7 +++---- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts b/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts index d12564050..59ff0bdce 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.spec.ts @@ -24,8 +24,8 @@ describe('GoSelectComponent', () => { GoRequiredTextModule, NgSelectModule, FormsModule, - ReactiveFormsModule, - ], + ReactiveFormsModule + ] }).compileComponents(); })); @@ -46,7 +46,7 @@ describe('GoSelectComponent', () => { component.items = [ { value: 1, label: 'Label 1' }, { value: 2, label: 'Label 2' }, - { value: 3, label: 'Label 3' }, + { value: 3, label: 'Label 3' } ]; component.onSelectAll(); @@ -59,7 +59,7 @@ describe('GoSelectComponent', () => { component.items = [ { id: 1, label: 'Label 1' }, { id: 2, label: 'Label 2' }, - { id: 3, label: 'Label 3' }, + { id: 3, label: 'Label 3' } ]; component.onSelectAll(); @@ -72,11 +72,11 @@ describe('GoSelectComponent', () => { component.items = [ { id: 1, label: 'banana' }, { id: 2, label: 'apple' }, - { id: 3, label: 'green apple' }, + { id: 3, label: 'green apple' } ]; const filteredItems = [ { id: 2, label: 'apple' }, - { id: 3, label: 'green apple' }, + { id: 3, label: 'green apple' } ]; component.handleInput({ items: filteredItems, term: 'apple' }); component.onSelectAll(); @@ -90,11 +90,11 @@ describe('GoSelectComponent', () => { { id: 1, label: 'banana' }, { id: 2, label: 'apple' }, { id: 3, label: 'green apple' }, - { id: 4, label: 'grapes' }, + { id: 4, label: 'grapes' } ]; const filteredItems = [ { id: 2, label: 'apple' }, - { id: 3, label: 'green apple' }, + { id: 3, label: 'green apple' } ]; component.handleInput({ items: filteredItems, term: 'apple' }); component.onSelectAll(); diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.ts b/projects/go-lib/src/lib/components/go-select/go-select.component.ts index c43e8494c..673a68241 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.ts +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.ts @@ -7,7 +7,7 @@ import { NgSelectComponent } from '@ng-select/ng-select'; encapsulation: ViewEncapsulation.None, selector: 'go-select', templateUrl: './go-select.component.html', - styleUrls: ['./go-select.component.scss'], + styleUrls: ['./go-select.component.scss'] }) export class GoSelectComponent extends GoFormBaseComponent @@ -39,12 +39,11 @@ export class GoSelectComponent @Input() virtualScroll: boolean = false; @Output() scrollToEnd: EventEmitter = new EventEmitter(); - @Output() scroll: EventEmitter<{ start: number; end: number }> = new EventEmitter<{ start: number; end: number }>(); + @Output() scroll: EventEmitter<{ start: number; end: number }> = new EventEmitter<{ start: number, end: number }>(); @ContentChild('goSelectOption') goSelectOption: TemplateRef; @ContentChild('goSelectOptionGroup') goSelectOptionGroup: TemplateRef; - @ContentChild('goSelectSelectedOption') - goSelectSelectedOption: TemplateRef; + @ContentChild('goSelectSelectedOption') goSelectSelectedOption: TemplateRef; private controlSubscription: Subscription; // store refined items after search From 512c9e22ff64195062414f182ee6787340d15554 Mon Sep 17 00:00:00 2001 From: vishal-tangoe Date: Tue, 23 May 2023 19:37:56 +0530 Subject: [PATCH 09/20] edge case handled while removing selected item --- .../src/lib/components/go-select/go-select.component.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.ts b/projects/go-lib/src/lib/components/go-select/go-select.component.ts index 673a68241..03a800348 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.ts +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.ts @@ -128,7 +128,9 @@ export class GoSelectComponent } private emptyRefinedItems(): void { - this.refinedItems = []; + if(!this.ngSelect.searchTerm) { + this.refinedItems = []; + } } handleInput(search: { term: string; items: any[] }) { @@ -150,8 +152,6 @@ export class GoSelectComponent this.scroll.emit($event); } - - onClose() { this.emptyRefinedItems(); } From 00d02d24209bdf0598f30002c9a2ee473b123355 Mon Sep 17 00:00:00 2001 From: vishal-tangoe Date: Wed, 24 May 2023 12:06:45 +0530 Subject: [PATCH 10/20] formatting changes --- .../go-lib/src/lib/components/go-select/go-select.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.ts b/projects/go-lib/src/lib/components/go-select/go-select.component.ts index 03a800348..ffb6cd774 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.ts +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.ts @@ -39,7 +39,7 @@ export class GoSelectComponent @Input() virtualScroll: boolean = false; @Output() scrollToEnd: EventEmitter = new EventEmitter(); - @Output() scroll: EventEmitter<{ start: number; end: number }> = new EventEmitter<{ start: number, end: number }>(); + @Output() scroll: EventEmitter<{ start: number, end: number }> = new EventEmitter<{ start: number, end: number }>(); @ContentChild('goSelectOption') goSelectOption: TemplateRef; @ContentChild('goSelectOptionGroup') goSelectOptionGroup: TemplateRef; @@ -96,7 +96,6 @@ export class GoSelectComponent this.bindValue ? item[this.bindValue] : item ); - const existing = Array.isArray(this.control.value) ? this.control.value : []; this.control.patchValue(existing.concat(refinedArr)); this.ngSelect.searchTerm = ''; From 028f54968e3e99307b5bcfea29ebd6c25ea1b8d2 Mon Sep 17 00:00:00 2001 From: vishal-tangoe Date: Wed, 24 May 2023 14:30:57 +0530 Subject: [PATCH 11/20] adding count to select all --- .../go-select/go-select.component.html | 6 +++-- .../go-select/go-select.component.spec.ts | 27 ++++++------------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/projects/go-lib/src/lib/components/go-select/go-select.component.html b/projects/go-lib/src/lib/components/go-select/go-select.component.html index c52e2857a..04ea84c82 100644 --- a/projects/go-lib/src/lib/components/go-select/go-select.component.html +++ b/projects/go-lib/src/lib/components/go-select/go-select.component.html @@ -34,7 +34,9 @@ [virtualScroll]="virtualScroll" (scrollToEnd)="onScrollToEnd()" (close)="onClose()" - (scroll)="onScroll($event)"> + (scroll)="onScroll($event)" + #select + > @@ -45,7 +47,7 @@ [ngClass]="{ 'go-select__select-all-button--dark' : theme === 'dark' }" *ngIf="showSelectAll && (control.value?.length < items?.length || typeahead)" > - Select All + Select {{!select.searchTerm || typeahead ? items.length : refinedItems.length}} Results