Skip to content

Commit 3e95cde

Browse files
authored
Merge branch 'master' into fix-#5418-8.1.x
2 parents 904bd0a + 8977f4c commit 3e95cde

File tree

5 files changed

+194
-65
lines changed

5 files changed

+194
-65
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ All notable changes for each version of this project will be documented in this
2828
- Replaces the current paginator in all grids. Can be used as a standalone component.
2929
- `IgxCombo`
3030
- Input `[overlaySettings]` - allows an object of type `OverlaySettings` to be passed. These custom overlay settings control how the drop-down list displays.
31+
- `IgxForOf` now offers usage of local variables `even`, `odd`, `first` and `last` to help with the distinction of the currently iterated element.
32+
3133

3234
## 8.0.2
3335
- `igx-list-theme` now have some new parameters for styling.

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

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,46 @@ describe('IgxForOf directive -', () => {
10861086
expect(children.length).toEqual(expectedElementsLength);
10871087
});
10881088
});
1089+
describe('even odd first last functions', () => {
1090+
configureTestSuite();
1091+
let fix: ComponentFixture<LocalVariablesComponent>;
1092+
1093+
beforeEach(async(() => {
1094+
TestBed.configureTestingModule({
1095+
declarations: [
1096+
TestIgxForOfDirective,
1097+
LocalVariablesComponent
1098+
],
1099+
imports: [IgxForOfModule]
1100+
}).compileComponents();
1101+
}));
1102+
1103+
beforeEach(() => {
1104+
fix = TestBed.createComponent(LocalVariablesComponent);
1105+
fix.detectChanges();
1106+
});
1107+
1108+
it('should differentiate even odd items', () => {
1109+
const allItems: DebugElement[] = fix.debugElement.queryAll(By.css('igx-display-container'))[0].children;
1110+
expect(allItems.length).toEqual(100);
1111+
for (let i = 0; i < allItems.length; i++) {
1112+
if (i === 0) {
1113+
expect(allItems[i].classes['first']).toBe(true);
1114+
}
1115+
if (i === allItems.length - 1) {
1116+
expect(allItems[i].classes['last']).toBe(true);
1117+
}
1118+
if (i % 2 === 0) {
1119+
expect(allItems[i].classes['even']).toBe(true);
1120+
} else {
1121+
expect(allItems[i].classes['odd']).toBe(true);
1122+
}
1123+
}
1124+
});
1125+
1126+
1127+
});
1128+
10891129
});
10901130

10911131
class DataGenerator {
@@ -1574,3 +1614,40 @@ export class NoWidthAndHeightComponent {
15741614
}
15751615
}
15761616
}
1617+
1618+
@Component({
1619+
template: `
1620+
<div class='container'>
1621+
<ng-template igxFor let-item [igxForOf]="data" #virtDirVertical
1622+
[igxForScrollOrientation]="'vertical'"
1623+
[igxForContainerSize]='"500px"'
1624+
[igxForItemSize]='itemSize'
1625+
let-rowIndex="index"
1626+
let-odd="odd"
1627+
let-even="even"
1628+
let-first="first"
1629+
let-last="last">
1630+
1631+
<div #markupItem
1632+
[ngClass]="{
1633+
first: first,
1634+
last: last,
1635+
even: even,
1636+
odd: odd
1637+
}"
1638+
[style.height]='itemSize'>
1639+
{{rowIndex}} : {{item.text}}
1640+
</div>
1641+
</ng-template>
1642+
</div>
1643+
`,
1644+
})
1645+
export class LocalVariablesComponent {
1646+
public data = [];
1647+
1648+
constructor() {
1649+
for (let i = 0; i < 100; i++) {
1650+
this.data.push({text: i + ''});
1651+
}
1652+
}
1653+
}

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

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,38 @@ import { VirtualHelperComponent } from './virtual.helper.component';
3131
import { IgxScrollInertiaModule } from './../scroll-inertia/scroll_inertia.directive';
3232
import { IgxForOfSyncService } from './for_of.sync.service';
3333

34+
/**
35+
* @publicApi
36+
*/
37+
export class IgxForOfContext<T> {
38+
constructor(
39+
public $implicit: T,
40+
public index: number,
41+
public count: number
42+
) {}
43+
44+
/**
45+
* A function that returns whether the element is the first or not
46+
*/
47+
get first(): boolean { return this.index === 0; }
48+
49+
/**
50+
* A function that returns whether the element is the last or not
51+
*/
52+
get last(): boolean { return this.index === this.count - 1; }
53+
54+
/**
55+
* A function that returns whether the element is even or not
56+
*/
57+
get even(): boolean { return this.index % 2 === 0; }
58+
59+
/**
60+
* A function that returns whether the element is odd or not
61+
*/
62+
get odd(): boolean { return !this.even; }
63+
64+
}
65+
3466
@Directive({ selector: '[igxFor][igxForOf]' })
3567
export class IgxForOfDirective<T> implements OnInit, OnChanges, DoCheck, OnDestroy {
3668

@@ -323,7 +355,7 @@ export class IgxForOfDirective<T> implements OnInit, OnChanges, DoCheck, OnDestr
323355
const input = this.igxForOf[i];
324356
const embeddedView = this.dc.instance._vcr.createEmbeddedView(
325357
this._template,
326-
{ $implicit: input, index: this.igxForOf.indexOf(input) }
358+
new IgxForOfContext<T>(input, this.getContextIndex(input), this.igxForOf.length)
327359
);
328360
this._embeddedViews.push(embeddedView);
329361
}
@@ -789,6 +821,7 @@ export class IgxForOfDirective<T> implements OnInit, OnChanges, DoCheck, OnDestr
789821
const cntx = embView.context;
790822
cntx.$implicit = input;
791823
cntx.index = this.getContextIndex(input);
824+
cntx.count = this.igxForOf.length;
792825
const view: ViewRef = this.dc.instance._vcr.detach(0);
793826
this.dc.instance._vcr.insert(view);
794827
this._embeddedViews.push(embView);
@@ -832,6 +865,7 @@ export class IgxForOfDirective<T> implements OnInit, OnChanges, DoCheck, OnDestr
832865
const cntx = (embView as EmbeddedViewRef<any>).context;
833866
cntx.$implicit = input;
834867
cntx.index = this.getContextIndex(input);
868+
cntx.count = this.igxForOf.length;
835869
}
836870
}
837871

@@ -903,6 +937,7 @@ export class IgxForOfDirective<T> implements OnInit, OnChanges, DoCheck, OnDestr
903937
const cntx = (embView as EmbeddedViewRef<any>).context;
904938
cntx.$implicit = input;
905939
cntx.index = this.getContextIndex(input);
940+
cntx.count = this.igxForOf.length;
906941
}
907942
this.dc.changeDetectorRef.detectChanges();
908943
if (prevChunkSize !== this.state.chunkSize) {
@@ -1165,7 +1200,7 @@ export class IgxForOfDirective<T> implements OnInit, OnChanges, DoCheck, OnDestr
11651200
const input = this.igxForOf[elemIndex];
11661201
const embeddedView = this.dc.instance._vcr.createEmbeddedView(
11671202
this._template,
1168-
{ $implicit: input, index: elemIndex }
1203+
new IgxForOfContext<T>(input, this.getContextIndex(input), this.igxForOf.length)
11691204
);
11701205

11711206
this._embeddedViews.push(embeddedView);
@@ -1516,7 +1551,7 @@ export class IgxGridForOfDirective<T> extends IgxForOfDirective<T> implements On
15161551
const input = this.igxForOf[elemIndex];
15171552
const embeddedView = this.dc.instance._vcr.createEmbeddedView(
15181553
this._template,
1519-
{ $implicit: input, index: elemIndex }
1554+
new IgxForOfContext<T>(input, this.getContextIndex(input), this.igxForOf.length)
15201555
);
15211556

15221557
this._embeddedViews.push(embeddedView);
@@ -1550,6 +1585,7 @@ export class IgxGridForOfDirective<T> extends IgxForOfDirective<T> implements On
15501585
const cntx = (embView as EmbeddedViewRef<any>).context;
15511586
cntx.$implicit = input;
15521587
cntx.index = this.getContextIndex(input);
1588+
cntx.count = this.igxForOf.length;
15531589
}
15541590
if (prevChunkSize !== this.state.chunkSize) {
15551591
this.onChunkLoad.emit(this.state);

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
position: relative;
66
overflow: hidden;
77
}
8+
.even { background-color: #1f1f1f; }
Lines changed: 75 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,87 @@
11
<div class="list-sample">
22
<article class="sample-column">
3-
<span>Vertical Virtualization</span>
4-
<br/>
5-
<div style='height:500px; position: relative; overflow: hidden'>
6-
<ng-template igxFor let-item [igxForOf]="data" #virtDirVertical
7-
[igxForScrollOrientation]="'vertical'"
8-
[igxForContainerSize]='"500px"'
9-
[igxForItemSize]='itemSize'
10-
let-rowIndex="index">
11-
<div [style.height]='itemSize'>{{rowIndex}} : {{item.text}}</div>
12-
</ng-template>
13-
</div>
14-
<button (click)="scrNextRow()">Scroll Next Row</button>
15-
<button (click)="scrPrevRow()">Scroll Prev Row</button>
16-
<button (click)="scrNextPage()">Scroll Next Page</button>
17-
<button (click)="scrPrevPage()">Scroll Prev Page</button>
18-
<div><input type='number' #input/><button (click)='scrScrollTo(input.value)'>Go To Index</button></div>
19-
<button (click)="verticalVisibleItemCount()">Get visible item count</button>
20-
<button (click)="changeItemSize()">Change Item Size</button>
3+
<span>Vertical Virtualization</span>
4+
<br/>
5+
<div style='height:500px; position: relative; overflow: hidden'>
6+
<ng-template igxFor let-item [igxForOf]="data" #virtDirVertical
7+
[igxForScrollOrientation]="'vertical'"
8+
[igxForContainerSize]='"500px"'
9+
[igxForItemSize]='itemSize'
10+
let-rowIndex="index">
11+
<div [style.height]='itemSize'>{{rowIndex}} : {{item.text}}</div>
12+
</ng-template>
13+
</div>
14+
<button (click)="scrNextRow()">Scroll Next Row</button>
15+
<button (click)="scrPrevRow()">Scroll Prev Row</button>
16+
<button (click)="scrNextPage()">Scroll Next Page</button>
17+
<button (click)="scrPrevPage()">Scroll Prev Page</button>
18+
<div><input type='number' #input/><button (click)='scrScrollTo(input.value)'>Go To Index</button></div>
19+
<button (click)="verticalVisibleItemCount()">Get visible item count</button>
20+
<button (click)="changeItemSize()">Change Item Size</button>
2121
</article>
2222
<article class="sample-column">
23-
<span>Horizontal Virtualization</span>
24-
<br/>
25-
<table>
26-
<tbody style='display:grid;'>
27-
<tr style='width:500px; height:100px;'>
28-
<div class='overflowContainer'>
29-
<ng-template igxFor let-item [igxForOf]="data" #virtDirHorizontal
30-
[igxForScrollOrientation]="'horizontal'"
31-
[igxForContainerSize]='"500px"'
32-
[igxForItemSize]='"200px"'
33-
let-rowIndex="index">
34-
<td [style.width.px]='200' [style.min-width.px]='200' style='height:100px;'>{{rowIndex}} : {{item.text}}</td>
35-
</ng-template>
36-
</div>
37-
</tr>
38-
</tbody>
39-
</table>
40-
<br/>
41-
<button (click)="scrNextCol()">Scroll Next Column</button>
42-
<button (click)="scrPrevCol()">Scroll Prev Column</button>
43-
<button (click)="scrNextHorizontalPage()">Scroll Next Horizontal Page</button>
44-
<button (click)="scrPrevHorizontalPage()">Scroll Prev Horizontal Page</button>
45-
<input (input)="scrHorizontalScrollTo($event.target.value)" placeholder="scroll to index"/>
46-
<button (click)="horizontalVisibleItemCount()">Get visible item count</button>
23+
<span>Horizontal Virtualization</span>
24+
<br/>
25+
<table>
26+
<tbody style='display:grid;'>
27+
<tr style='width:500px; height:100px;'>
28+
<div style='position: relative; overflow: hidden'>
29+
<ng-template igxFor let-item [igxForOf]="data" #virtDirHorizontal
30+
[igxForScrollOrientation]="'horizontal'"
31+
[igxForContainerSize]='"500px"'
32+
let-rowIndex="index">
33+
<td [style.width.px]='item.width' [style.min-width.px]='item.width' style='height:100px;'>{{rowIndex}} : {{item.text}}</td>
34+
</ng-template>
35+
</div>
36+
</tr>
37+
</tbody>
38+
</table>
39+
<button (click)="scrNextCol()">Scroll Next Column</button>
40+
<button (click)="scrPrevCol()">Scroll Prev Column</button>
41+
<button (click)="scrNextHorizontalPage()">Scroll Next Horizontal Page</button>
42+
<button (click)="scrPrevHorizontalPage()">Scroll Prev Horizontal Page</button>
43+
<input (input)="scrHorizontalScrollTo($event.target.value)" placeholder="scroll to index"/>
44+
<button (click)="horizontalVisibleItemCount()">Get visible item count</button>
4745
</article>
4846
<article class="sample-column">
4947
<span>Variable heights</span>
5048
<br/>
5149
<div style='height:500px; position: relative; overflow: hidden'>
52-
<ng-template igxFor let-item [igxForOf]="data" #virtDirVariableVertical [igxForTrackBy]='trackByKey'
53-
[igxForScrollOrientation]="'vertical'"
54-
[igxForContainerSize]='"500px"'
55-
[igxForItemSize]='"100px"'
56-
let-rowIndex="index">
57-
<div [style.height.px]='item.height'>{{rowIndex}} : {{item.text}}</div>
58-
</ng-template>
59-
</div>
60-
</article>
50+
<ng-template igxFor let-item [igxForOf]="data" #virtDirVariableVertical [igxForTrackBy]='trackByKey'
51+
[igxForScrollOrientation]="'vertical'"
52+
[igxForContainerSize]='"500px"'
53+
[igxForItemSize]='"100px"'
54+
let-rowIndex="index">
55+
<div [style.height.px]='item.height'>{{rowIndex}} : {{item.text}}</div>
56+
</ng-template>
57+
</div>
58+
</article>
59+
<article class="sample-column">
60+
<span><i>Even</i> variable</span>
61+
<br/>
62+
<div style='height:500px; position: relative; overflow: hidden'>
63+
<ng-template igxFor let-item [igxForOf]="data" #virtDirVertical
64+
[igxForScrollOrientation]="'vertical'"
65+
[igxForContainerSize]='"500px"'
66+
[igxForItemSize]='itemSize'
67+
let-rowIndex="index"
68+
let-odd="odd"
69+
let-even="even">
70+
<div [ngClass]="{even: even}" [style.height]='itemSize'>{{rowIndex}} : {{item.text}}</div>
71+
</ng-template>
72+
</div>
73+
</article>
6174
<article class="sample-column">
62-
<span>Remote Virtualization</span>
63-
<br/>
64-
<div style='height:500px; position: relative; overflow: hidden'>
65-
<ng-template igxFor let-item [igxForOf]="remoteData | async" (onChunkPreload)="chunkLoading($event)"
66-
[igxForScrollOrientation]="'vertical'"
67-
[igxForContainerSize]='"500px"'
68-
[igxForItemSize]='"50px"'
69-
let-rowIndex="index" #virtDirRemote>
70-
<div style='height:50px;'>Index: {{rowIndex}}, ID: {{item.ProductID}}, Name : {{item.ProductName}}</div>
71-
</ng-template>
72-
</div>
75+
<span>Remote Virtualization</span>
76+
<br/>
77+
<div style='height:500px; position: relative; overflow: hidden'>
78+
<ng-template igxFor let-item [igxForOf]="remoteData | async" (onChunkPreload)="chunkLoading($event)"
79+
[igxForScrollOrientation]="'vertical'"
80+
[igxForContainerSize]='"500px"'
81+
[igxForItemSize]='"50px"'
82+
let-rowIndex="index" #virtDirRemote>
83+
<div style='height:50px;'>Index: {{rowIndex}}, ID: {{item.ProductID}}, Name : {{item.ProductName}}</div>
84+
</ng-template>
85+
</div>
7386
</article>
7487
</div>

0 commit comments

Comments
 (0)