Skip to content

Commit 6dede8c

Browse files
Add Simple Combo remote binding sample and filtering to Combo remote binding sample (#3128)
* (feat): Adding Simple Combo remote binding sample and filtering to the Combo remote binding sample * (feat): Adding check for the start index in order to present the combo items correctly when the combo has been filtered * (feat): Adjusting the scroll position when the combo is opened * (feat): Adjusting the scroll position only when the combo is filtered * (feat): Adjusting the format * refactor(simple-combo): Refactoring some format issues * refactor(combo): Displaying the last selected item when the combo is opened * refactor(combo): Moving the logic that checks for filtering from selectionChanging to searchInputUpdate event * refactor(combo): Removing unnecessary filtering logic * refactor(combo): Moving data fetching logic from onOpening to onClosed to reduce flickering when loading data * refactor(combo): Adjusting the chunk size while search input is changing and the scroll position when the last item is selected
1 parent 7612eda commit 6dede8c

8 files changed

Lines changed: 198 additions & 13 deletions

src/app/lists/combo/combo-remote/combo-remote.component.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
[valueKey]="'ProductID'"
66
[displayKey]="'ProductName'"
77
(dataPreLoad)="dataLoading()"
8-
(searchInputUpdate)="searchInput($event)"
8+
(searchInputUpdate)="handleSearchInputUpdate($event)"
99
(selectionChanging)="handleSelectionChanging($event)"
10-
(closing)="onClosing()" (opening)="onOpening()"
10+
(closing)="onClosing()" (opened)="onOpened()"
11+
(closed)="onClosed()"
1112
placeholder="Location(s)"
12-
[filterable]="false">
13+
[filterable]="true">
1314
</igx-combo>
1415
<igx-toast #loadingToast></igx-toast>

src/app/lists/combo/combo-remote/combo-remote.component.ts

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ export class ComboRemoteComponent implements OnInit, AfterViewInit {
2323

2424
private searchText: string = null;
2525
private defaultVirtState: IForOfState = { chunkSize: 6, startIndex: 0 };
26-
26+
private currentVirtState: IForOfState = { chunkSize: 6, startIndex: 0 };
27+
private itemID: number = 1;
28+
private itemCount: number = 0;
2729
private hasSelection: boolean;
30+
private additionalScroll: number = 0;
2831

2932
constructor(
3033
private remoteService: RemoteNWindService,
@@ -42,6 +45,7 @@ export class ComboRemoteComponent implements OnInit, AfterViewInit {
4245
};
4346
this.remoteService.getData(initSize, null, (data) => {
4447
this.remoteCombo.totalItemCount = data['@odata.count'];
48+
this.itemCount = this.remoteCombo.totalItemCount;
4549
});
4650
}
4751

@@ -65,32 +69,61 @@ export class ComboRemoteComponent implements OnInit, AfterViewInit {
6569
);
6670
}
6771

68-
public searchInput(searchData: IComboSearchInputEventArgs) {
72+
public handleSearchInputUpdate(searchData: IComboSearchInputEventArgs) {
73+
this.currentVirtState.startIndex = 0;
74+
this.currentVirtState.chunkSize = Math.ceil(this.remoteCombo.itemsMaxHeight / this.remoteCombo.itemHeight);
6975
this.searchText = searchData?.searchText || '';
7076
this.remoteService.getData(
71-
this.searchText ? this.remoteCombo.virtualizationState : this.defaultVirtState,
77+
this.searchText ? this.currentVirtState : this.defaultVirtState,
7278
this.searchText,
7379
(data) => {
7480
this.remoteCombo.totalItemCount = data['@odata.count'];
7581
}
7682
);
7783
}
7884

79-
public onOpening() {
85+
public onOpened() {
86+
const scroll: number = this.remoteCombo.virtualScrollContainer.getScrollForIndex(this.itemID - 1);
87+
this.remoteCombo.virtualScrollContainer.scrollPosition = scroll + this.additionalScroll;
88+
this.cdr.detectChanges();
89+
}
90+
91+
public onClosing() {
92+
this.searchText = '';
93+
}
94+
95+
public onClosed() {
96+
this.currentVirtState.startIndex = (this.itemID || 1) - 1;
8097
this.remoteService.getData(
81-
this.hasSelection ? this.remoteCombo.virtualizationState : this.defaultVirtState,
98+
this.currentVirtState,
8299
this.searchText,
83100
(data) => {
84101
this.remoteCombo.totalItemCount = data['@odata.count'];
102+
this.cdr.detectChanges();
85103
}
86104
);
87105
}
88106

89-
public onClosing() {
90-
this.searchText = '';
91-
}
92-
93107
public handleSelectionChanging(evt: IComboSelectionChangingEventArgs) {
94108
this.hasSelection = !!evt?.newSelection.length;
109+
110+
if (!this.hasSelection) {
111+
this.itemID = 1;
112+
this.currentVirtState = this.defaultVirtState;
113+
return;
114+
}
115+
116+
const currentSelection = evt.newSelection[evt.newSelection.length - 1]
117+
this.currentVirtState.chunkSize = Math.ceil(this.remoteCombo.itemsMaxHeight / this.remoteCombo.itemHeight);
118+
119+
this.itemCount === currentSelection ?
120+
this.additionalScroll = this.remoteCombo.itemHeight :
121+
this.additionalScroll = 0;
122+
123+
if (this.itemCount - currentSelection >= this.currentVirtState.chunkSize - 1) {
124+
this.itemID = this.currentVirtState.startIndex = currentSelection;
125+
} else {
126+
this.itemID = this.currentVirtState.startIndex = this.itemCount - (this.currentVirtState.chunkSize - 1);
127+
}
95128
}
96129
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<igx-simple-combo #remoteSimpleCombo class="combo"
2+
[itemsMaxHeight]="250"
3+
[itemHeight]="48"
4+
[data]="rData | async"
5+
[valueKey]="'ProductID'"
6+
[displayKey]="'ProductName'"
7+
placeholder="Product"
8+
(dataPreLoad)="dataLoading()"
9+
(closing)="onClosing()" (opened)="onOpened()"
10+
(closed)="onClosed()"
11+
(selectionChanging)="handleSelectionChanging($event)"
12+
(searchInputUpdate)="handleSearchInputUpdate($event)">
13+
</igx-simple-combo>
14+
<igx-toast #loadingToast></igx-toast>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.combo {
2+
margin: 8px;
3+
width: 430px;
4+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { AfterViewInit, ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
2+
import { IComboSearchInputEventArgs, IForOfState, IgxSimpleComboComponent, IgxToastComponent, ISimpleComboSelectionChangingEventArgs, VerticalAlignment } from 'igniteui-angular';
3+
import { RemoteNWindService } from '../../../services/remoteNwind.service';
4+
5+
@Component({
6+
providers: [RemoteNWindService],
7+
selector: 'app-simple-combo-remote',
8+
templateUrl: './simple-combo-remote.component.html',
9+
styleUrls: ['./simple-combo-remote.component.scss']
10+
})
11+
export class SimpleComboRemoteComponent implements OnInit, AfterViewInit {
12+
@ViewChild('loadingToast')
13+
public loadingToast: IgxToastComponent;
14+
15+
@ViewChild('remoteSimpleCombo', { read: IgxSimpleComboComponent, static: true })
16+
public remoteSimpleCombo: IgxSimpleComboComponent;
17+
18+
public prevRequest: any;
19+
public rData: any;
20+
private searchText: string = null;
21+
private defaultVirtState: IForOfState = { chunkSize: 6, startIndex: 0 };
22+
private currentVirtState: IForOfState = { chunkSize: 6, startIndex: 0 };
23+
private itemID = 1;
24+
private itemCount: number = 0;
25+
private hasSelection: boolean;
26+
private additionalScroll: number = 0;
27+
28+
constructor(
29+
private remoteService: RemoteNWindService,
30+
public cdr: ChangeDetectorRef
31+
) { }
32+
33+
public ngOnInit() {
34+
this.rData = this.remoteService.remoteData;
35+
}
36+
37+
public ngAfterViewInit() {
38+
const initSize = {
39+
startIndex: 0,
40+
chunkSize: Math.ceil(this.remoteSimpleCombo.itemsMaxHeight / this.remoteSimpleCombo.itemHeight)
41+
};
42+
this.remoteService.getData(initSize, null, (data) => {
43+
this.remoteSimpleCombo.totalItemCount = data['@odata.count'];
44+
this.itemCount = this.remoteSimpleCombo.totalItemCount;
45+
});
46+
}
47+
48+
public dataLoading() {
49+
if (this.prevRequest) {
50+
this.prevRequest.unsubscribe();
51+
}
52+
this.loadingToast.positionSettings.verticalDirection = VerticalAlignment.Middle;
53+
this.loadingToast.autoHide = false;
54+
this.loadingToast.open('Loading Remote Data...');
55+
this.cdr.detectChanges();
56+
57+
this.prevRequest = this.remoteService.getData(
58+
this.remoteSimpleCombo.virtualizationState,
59+
this.searchText,
60+
(data) => {
61+
this.remoteSimpleCombo.totalItemCount = data['@odata.count'];
62+
this.loadingToast.close();
63+
this.cdr.detectChanges();
64+
}
65+
);
66+
}
67+
68+
public onOpened() {
69+
const scroll: number = this.remoteSimpleCombo.virtualScrollContainer.getScrollForIndex(this.itemID - 1);
70+
this.remoteSimpleCombo.virtualScrollContainer.scrollPosition = scroll + this.additionalScroll;
71+
this.cdr.detectChanges();
72+
}
73+
74+
public onClosing() {
75+
this.searchText = '';
76+
}
77+
78+
public onClosed() {
79+
this.currentVirtState.startIndex = (this.itemID || 1) - 1;
80+
this.remoteService.getData(
81+
this.currentVirtState,
82+
this.searchText,
83+
(data) => {
84+
this.remoteSimpleCombo.totalItemCount = data['@odata.count'];
85+
this.cdr.detectChanges();
86+
}
87+
);
88+
}
89+
90+
public handleSelectionChanging(evt: ISimpleComboSelectionChangingEventArgs) {
91+
this.hasSelection = evt.newSelection !== undefined;
92+
93+
if (!this.hasSelection) {
94+
this.itemID = 1;
95+
this.currentVirtState = this.defaultVirtState;
96+
return;
97+
}
98+
99+
this.currentVirtState.chunkSize = Math.ceil(this.remoteSimpleCombo.itemsMaxHeight / this.remoteSimpleCombo.itemHeight);
100+
101+
this.itemCount === evt.newSelection ?
102+
this.additionalScroll = this.remoteSimpleCombo.itemHeight :
103+
this.additionalScroll = 0;
104+
105+
if (this.itemCount - evt.newSelection >= this.currentVirtState.chunkSize - 1) {
106+
this.itemID = this.currentVirtState.startIndex = evt.newSelection;
107+
} else {
108+
this.itemID = this.currentVirtState.startIndex = this.itemCount - (this.currentVirtState.chunkSize - 1);
109+
}
110+
}
111+
112+
public handleSearchInputUpdate(searchData: IComboSearchInputEventArgs) {
113+
this.currentVirtState.startIndex = 0;
114+
this.currentVirtState.chunkSize = Math.ceil(this.remoteSimpleCombo.itemsMaxHeight / this.remoteSimpleCombo.itemHeight);
115+
this.searchText = searchData?.searchText || '';
116+
this.remoteService.getData(
117+
this.searchText ? this.currentVirtState : this.defaultVirtState,
118+
this.searchText,
119+
(data) => {
120+
this.remoteSimpleCombo.totalItemCount = data['@odata.count'];
121+
}
122+
);
123+
}
124+
}

src/app/lists/lists-routes-data.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const listsRoutesData = {
1313
'simple-combo-usage': { displayName: 'Usage Simple Combo', parentName: 'Combo'},
1414
'simple-combo-cascading': { displayName: 'Cascading Simple Combo', parentName: 'Combo'},
1515
'simple-combo-styling': { displayName: 'Simple Combo Styling', parentName: 'Combo'},
16+
'simple-combo-remote': { displayName: 'Remote Simple Combo', parentName: 'Combo'},
1617
// eslint-disable-next-line quote-props
1718
'list': { displayName: 'List Overview', parentName: 'List' },
1819
'list-sample-2': { displayName: 'List Item Header', parentName: 'List' },

src/app/lists/lists-routing.module.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { SimpleComboUsageComponent } from './combo/simple-combo-usage/simple-com
2626
import { SimpleComboCascadingComponent } from './combo/simple-combo-cascading/simple-combo-cascading.component';
2727
import { SimpleComboStylingComponent } from './combo/simple-combo-styling/simple-combo-styling.component';
2828
import { ListItemSelectionComponent } from './list/list-item-selection/list-item-selection.component';
29+
import { SimpleComboRemoteComponent } from './combo/simple-combo-remote/simple-combo-remote.component';
2930

3031
export const listsRoutes: Routes = [
3132
{
@@ -88,6 +89,11 @@ export const listsRoutes: Routes = [
8889
data: listsRoutesData['simple-combo-styling'],
8990
path: 'simple-combo-styling'
9091
},
92+
{
93+
component: SimpleComboRemoteComponent,
94+
data: listsRoutesData['simple-combo-remote'],
95+
path: 'simple-combo-remote'
96+
},
9197
{
9298
component: ListComponent,
9399
// tslint:disable-next-line:no-string-literal

src/app/lists/lists.module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import { SimpleComboUsageComponent } from './combo/simple-combo-usage/simple-com
4848
import { SimpleComboCascadingComponent } from './combo/simple-combo-cascading/simple-combo-cascading.component';
4949
import { SimpleComboStylingComponent } from './combo/simple-combo-styling/simple-combo-styling.component';
5050
import { ListItemSelectionComponent } from './list/list-item-selection/list-item-selection.component';
51+
import { SimpleComboRemoteComponent } from './combo/simple-combo-remote/simple-combo-remote.component';
5152

5253
@NgModule({
5354
declarations: [
@@ -75,7 +76,8 @@ import { ListItemSelectionComponent } from './list/list-item-selection/list-item
7576
SimpleComboStylingComponent,
7677
TreeBasicSampleComponent,
7778
TreeAdvancedSampleComponent,
78-
ListItemSelectionComponent
79+
ListItemSelectionComponent,
80+
SimpleComboRemoteComponent
7981
],
8082
imports: [
8183
CommonModule,

0 commit comments

Comments
 (0)