Skip to content

Commit cf4da46

Browse files
authored
Merge pull request #6516 from IgniteUI/dkamburov/expose-totalItemCount
feat(igxFor): Add input igxForOfTotalItemCount to be settable in template
2 parents 2b866c1 + 0ec7763 commit cf4da46

File tree

7 files changed

+139
-1
lines changed

7 files changed

+139
-1
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,13 @@ All notable changes for each version of this project will be documented in this
126126
```
127127
- RTL support
128128

129+
- `IgxForOf`
130+
- `IgxForTotalItemCount` input is added for the cases when the data is from remote services. This will allow setting the count of the items through the template. And gives the opportunity for the developers to use AsyncPipe for this option:
131+
```html
132+
<ng-template igxFor let-item [igxForOf]="data | async" [igxForTotalItemCount]="count | async"
133+
[igxForContainerSize]="'500px'" [igxForItemSize]="'50px'"></ng-template>
134+
```
135+
129136
## 8.2.6
130137

131138
### New Features

projects/igniteui-angular/src/lib/directives/for-of/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ When the contents of the iterator changes, `igxForOf` makes the corresponding ch
6868
| igxForScrollContainer | string | Only the strings `vertical` and `horizontal` are valid and specify the scroll orientation |
6969
| igxForContainerSize | string | The px-affixed size of the container along the axis of scrolling |
7070
| igxForScrollContainer | IgxForOf | Optionally pass the parent `igxForOf` instance to create a virtual template scrolling both horizontally and vertically |
71+
| igxForTotalItemCount | number | The total count of the virtual data items, when using remote service. This is exposed to allow setting the count of the items through the template |
7172

7273
### Outputs
7374

projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.spec.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,58 @@ describe('IgxForOf directive -', () => {
10751075
}
10761076
});
10771077
});
1078+
1079+
describe('remote virtual component with specified igxForTotalItemCount', () => {
1080+
configureTestSuite();
1081+
let fix: ComponentFixture<RemoteVirtCountComponent>;
1082+
1083+
beforeEach(async(() => {
1084+
TestBed.configureTestingModule({
1085+
declarations: [
1086+
TestIgxForOfDirective,
1087+
RemoteVirtCountComponent
1088+
],
1089+
imports: [IgxForOfModule]
1090+
}).compileComponents();
1091+
}));
1092+
1093+
beforeEach(() => {
1094+
fix = TestBed.createComponent(RemoteVirtCountComponent);
1095+
fix.componentRef.hostView.detectChanges();
1096+
fix.detectChanges();
1097+
1098+
displayContainer = fix.nativeElement.querySelector('igx-display-container');
1099+
verticalScroller = fix.nativeElement.querySelector('igx-virtual-helper');
1100+
});
1101+
1102+
it('should apply remote virtualization correctly', async () => {
1103+
// verify data is loaded
1104+
let rowsRendered = displayContainer.children;
1105+
let data = fix.componentInstance.data.source.getValue();
1106+
for (let i = 0; i < rowsRendered.length; i++) {
1107+
expect(rowsRendered[i].textContent.trim())
1108+
.toBe(data[i].toString());
1109+
}
1110+
1111+
// scroll down
1112+
expect(() => {
1113+
verticalScroller.scrollTop = 10000;
1114+
fix.detectChanges();
1115+
fix.componentRef.hostView.detectChanges();
1116+
}).not.toThrow();
1117+
1118+
await wait();
1119+
1120+
// verify data is loaded
1121+
rowsRendered = displayContainer.children;
1122+
data = fix.componentInstance.data.source.getValue();
1123+
for (let i = fix.componentInstance.parentVirtDir.state.startIndex; i < rowsRendered.length; i++) {
1124+
expect(rowsRendered[i].textContent.trim())
1125+
.toBe(data[i].toString());
1126+
}
1127+
});
1128+
});
1129+
10781130
describe('no width and height component', () => {
10791131
configureTestSuite();
10801132
let fix: ComponentFixture<NoWidthAndHeightComponent>;
@@ -1518,10 +1570,15 @@ export class LocalService {
15181570
private _records: BehaviorSubject<any[]>;
15191571
private dataStore: any[];
15201572

1573+
public count: Observable<number>;
1574+
private _count: BehaviorSubject<number>;
1575+
15211576
constructor() {
15221577
this.dataStore = [];
15231578
this._records = new BehaviorSubject([]);
15241579
this.records = this._records.asObservable();
1580+
this._count = new BehaviorSubject(null);
1581+
this.count = this._count.asObservable();
15251582
}
15261583

15271584
public getData(data?: IForOfState, cb?: (any) => void): any {
@@ -1534,6 +1591,11 @@ export class LocalService {
15341591
}
15351592
}
15361593

1594+
public getCount() {
1595+
const count = 1000;
1596+
this._count.next(count);
1597+
}
1598+
15371599
public generateData(start, end) {
15381600
const dummyData = [];
15391601
for (let i = start; i < end; i++) {
@@ -1588,6 +1650,51 @@ export class RemoteVirtualizationComponent implements OnInit, AfterViewInit {
15881650
}
15891651
}
15901652

1653+
@Component({
1654+
template: `
1655+
<div #container [style.width]='width' [style.height]='height'>
1656+
<ng-template #scrollContainer let-rowData [igxForOf]="data | async" igxForTest
1657+
[igxForTotalItemCount]="count | async"
1658+
[igxForContainerSize]='height'
1659+
[igxForItemSize]='"50px"'
1660+
(onChunkPreload)="dataLoading($event)">
1661+
<div [style.display]="'flex'" [style.height]="'50px'">
1662+
{{rowData}}
1663+
</div>
1664+
</ng-template>
1665+
</div>
1666+
`,
1667+
providers: [LocalService]
1668+
})
1669+
export class RemoteVirtCountComponent implements OnInit, AfterViewInit {
1670+
public height = '500px';
1671+
public data;
1672+
public count: Observable<number>;
1673+
1674+
@ViewChild('scrollContainer', { read: TestIgxForOfDirective, static: true })
1675+
public parentVirtDir: TestIgxForOfDirective<any>;
1676+
1677+
@ViewChild('container', { read: ViewContainerRef, static: true })
1678+
public container: ViewContainerRef;
1679+
1680+
constructor(private localService: LocalService) { }
1681+
public ngOnInit(): void {
1682+
this.data = this.localService.records;
1683+
this.count = this.localService.count;
1684+
}
1685+
1686+
public ngAfterViewInit() {
1687+
this.localService.getCount();
1688+
this.localService.getData(this.parentVirtDir.state);
1689+
}
1690+
1691+
dataLoading(evt) {
1692+
this.localService.getData(evt, () => {
1693+
this.parentVirtDir.cdr.detectChanges();
1694+
});
1695+
}
1696+
}
1697+
15911698
@Component({
15921699
template: `
15931700
<div class="container">

projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,21 @@ export class IgxForOfDirective<T> implements OnInit, OnChanges, DoCheck, OnDestr
141141
@Input()
142142
public igxForItemSize: any;
143143

144+
/**
145+
* The total count of the virtual data items, when using remote service.
146+
* Similar to the property totalItemCount, but this will allow setting the data count into the template.
147+
* ```html
148+
* <ng-template igxFor let-item [igxForOf]="data | async" [igxForTotalItemCount]="count | async"
149+
* [igxForContainerSize]="'500px'" [igxForItemSize]="'50px'"></ng-template>
150+
* ```
151+
*/
152+
@Input()
153+
get igxForTotalItemCount(): number {
154+
return this.totalItemCount;
155+
}
156+
set igxForTotalItemCount(value: number) {
157+
this.totalItemCount = value;
158+
}
144159
/**
145160
* @hidden
146161
*/

src/app/shared/remote.service.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { HttpClient } from '@angular/common/http';
66
@Injectable()
77
export class RemoteService {
88

9+
totalCount: Observable<number>;
10+
_totalCount: BehaviorSubject<number>;
911
remoteData: Observable<any[]>;
1012
_remoteData: BehaviorSubject<any[]>;
1113
url = `https://services.odata.org/V4/Northwind/Northwind.svc/Products`;
@@ -14,6 +16,8 @@ export class RemoteService {
1416
constructor(private http: HttpClient) {
1517
this._remoteData = new BehaviorSubject([]);
1618
this.remoteData = this._remoteData.asObservable();
19+
this._totalCount = new BehaviorSubject(null);
20+
this.totalCount = this._totalCount.asObservable();
1721
}
1822

1923
nullData() {
@@ -31,6 +35,7 @@ export class RemoteService {
3135
)
3236
.subscribe(d => {
3337
this._remoteData.next(d['value']);
38+
this._totalCount.next(d['@odata.count']);
3439
if (cb) {
3540
cb(d);
3641
}

src/app/virtual-for-directive/virtual-for.sample.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
[igxForScrollOrientation]="'vertical'"
8181
[igxForContainerSize]='"500px"'
8282
[igxForItemSize]='"50px"'
83+
[igxForTotalItemCount]="totalCount | async"
8384
let-rowIndex="index" #virtDirRemote>
8485
<div style='height:50px;'>Index: {{rowIndex}}, ID: {{item.ProductID}}, Name : {{item.ProductName}}</div>
8586
</ng-template>

src/app/virtual-for-directive/virtual-for.sample.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export class VirtualForSampleComponent implements OnInit, AfterViewInit {
1313
search1: string;
1414
data = [];
1515
remoteData: any;
16+
totalCount: any;
1617
options = {};
1718
prevRequest: any;
1819
itemSize = '100px';
@@ -45,6 +46,7 @@ export class VirtualForSampleComponent implements OnInit, AfterViewInit {
4546

4647
ngOnInit(): void {
4748
this.remoteData = this.remoteService.remoteData;
49+
this.totalCount = this.remoteService.totalCount;
4850
const data = [{
4951
key: 1,
5052
avatar: 'assets/images/avatar/1.jpg',
@@ -136,7 +138,7 @@ export class VirtualForSampleComponent implements OnInit, AfterViewInit {
136138

137139
ngAfterViewInit() {
138140
this.remoteService.getData(this.virtDirRemote.state, (data) => {
139-
this.virtDirRemote.totalItemCount = data['@odata.count'];
141+
//this.virtDirRemote.totalItemCount = data['@odata.count'];
140142
});
141143
}
142144
chunkLoading(evt) {

0 commit comments

Comments
 (0)