Skip to content

Commit 5f9c59a

Browse files
author
vakrilov
committed
List View template selector
1 parent a5ecaa2 commit 5f9c59a

File tree

6 files changed

+211
-50
lines changed

6 files changed

+211
-50
lines changed

Diff for: nativescript-angular/directives.ts

+15-14
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import {ListViewComponent, SetupItemViewArgs} from './directives/list-view-comp';
2-
import {TabViewDirective, TabViewItemDirective} from './directives/tab-view';
3-
import {ActionBarComponent, ActionBarScope, ActionItemDirective, NavigationButtonDirective} from './directives/action-bar';
4-
import {AndroidFilterComponent, IosFilterComponent} from './directives/platform-filters';
1+
import { ListViewComponent, TemplateKeyDirective } from './directives/list-view-comp';
2+
import { TabViewDirective, TabViewItemDirective } from './directives/tab-view';
3+
import { ActionBarComponent, ActionBarScope, ActionItemDirective, NavigationButtonDirective } from './directives/action-bar';
4+
import { AndroidFilterComponent, IosFilterComponent } from './directives/platform-filters';
55

66
export const NS_DIRECTIVES = [
77
ListViewComponent,
8+
TemplateKeyDirective,
89
TabViewDirective,
910
TabViewItemDirective,
1011
ActionBarComponent,
@@ -15,13 +16,13 @@ export const NS_DIRECTIVES = [
1516
IosFilterComponent,
1617
];
1718

18-
export {ListViewComponent, SetupItemViewArgs} from './directives/list-view-comp';
19-
export {TextValueAccessor} from './value-accessors/text-value-accessor';
20-
export {CheckedValueAccessor} from './value-accessors/checked-value-accessor';
21-
export {DateValueAccessor} from './value-accessors/date-value-accessor';
22-
export {TimeValueAccessor} from './value-accessors/time-value-accessor';
23-
export {NumberValueAccessor} from './value-accessors/number-value-accessor';
24-
export {SelectedIndexValueAccessor} from './value-accessors/selectedIndex-value-accessor';
25-
export {TabViewDirective, TabViewItemDirective} from './directives/tab-view';
26-
export {ActionBarComponent, ActionBarScope, ActionItemDirective, NavigationButtonDirective} from './directives/action-bar';
27-
export {AndroidFilterComponent, IosFilterComponent} from './directives/platform-filters';
19+
export { ListViewComponent, SetupItemViewArgs, TemplateKeyDirective } from './directives/list-view-comp';
20+
export { TextValueAccessor } from './value-accessors/text-value-accessor';
21+
export { CheckedValueAccessor } from './value-accessors/checked-value-accessor';
22+
export { DateValueAccessor } from './value-accessors/date-value-accessor';
23+
export { TimeValueAccessor } from './value-accessors/time-value-accessor';
24+
export { NumberValueAccessor } from './value-accessors/number-value-accessor';
25+
export { SelectedIndexValueAccessor } from './value-accessors/selectedIndex-value-accessor';
26+
export { TabViewDirective, TabViewItemDirective } from './directives/tab-view';
27+
export { ActionBarComponent, ActionBarScope, ActionItemDirective, NavigationButtonDirective } from './directives/action-bar';
28+
export { AndroidFilterComponent, IosFilterComponent } from './directives/platform-filters';

Diff for: nativescript-angular/directives/list-view-comp.ts

+82-21
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import {
22
Component,
3+
Directive,
4+
Input,
35
DoCheck,
46
OnDestroy,
7+
AfterContentInit,
58
ElementRef,
69
ViewContainerRef,
710
TemplateRef,
@@ -13,14 +16,16 @@ import {
1316
EventEmitter,
1417
ViewChild,
1518
Output,
16-
ChangeDetectionStrategy } from '@angular/core';
17-
import {isBlank} from "../lang-facade";
18-
import {isListLikeIterable} from "../collection-facade";
19-
import {ListView} from 'ui/list-view';
20-
import {View} from 'ui/core/view';
21-
import {ObservableArray} from 'data/observable-array';
22-
import {LayoutBase} from 'ui/layouts/layout-base';
23-
import {listViewLog} from "../trace";
19+
Host,
20+
ChangeDetectionStrategy
21+
} from '@angular/core';
22+
import { isBlank } from "../lang-facade";
23+
import { isListLikeIterable } from "../collection-facade";
24+
import { ListView } from 'ui/list-view';
25+
import { View, KeyedTemplate } from 'ui/core/view';
26+
import { ObservableArray } from 'data/observable-array';
27+
import { LayoutBase } from 'ui/layouts/layout-base';
28+
import { listViewLog } from "../trace";
2429

2530
const NG_VIEW = "_ngViewRef";
2631

@@ -51,14 +56,15 @@ export interface SetupItemViewArgs {
5156
inputs: ['items'],
5257
changeDetection: ChangeDetectionStrategy.OnPush
5358
})
54-
export class ListViewComponent implements DoCheck, OnDestroy {
59+
export class ListViewComponent implements DoCheck, OnDestroy, AfterContentInit {
5560
public get nativeElement(): ListView {
5661
return this.listView;
5762
}
5863

5964
private listView: ListView;
6065
private _items: any;
6166
private _differ: IterableDiffer;
67+
private _templateMap: Map<string, KeyedTemplate>;
6268

6369
@ViewChild('loader', { read: ViewContainerRef }) loader: ViewContainerRef;
6470

@@ -68,7 +74,7 @@ export class ListViewComponent implements DoCheck, OnDestroy {
6874

6975
set items(value: any) {
7076
this._items = value;
71-
var needDiffer = true;
77+
let needDiffer = true;
7278
if (value instanceof ObservableArray) {
7379
needDiffer = false;
7480
}
@@ -87,12 +93,51 @@ export class ListViewComponent implements DoCheck, OnDestroy {
8793
this.listView.on("itemLoading", this.onItemLoading, this);
8894
}
8995

96+
ngAfterContentInit() {
97+
listViewLog("ListView.ngAfterContentInit()");
98+
this.setItemTemplates();
99+
}
100+
90101
ngOnDestroy() {
91102
this.listView.off("itemLoading", this.onItemLoading, this);
92103
}
93104

105+
private setItemTemplates() {
106+
if (this._templateMap) {
107+
listViewLog("Setting templates");
108+
109+
const templates: KeyedTemplate[] = [];
110+
this._templateMap.forEach(value => {
111+
templates.push(value);
112+
});
113+
this.listView.itemTemplates = templates;
114+
}
115+
}
116+
117+
public registerTemplate(key: string, template: TemplateRef<ListItemContext>) {
118+
listViewLog("registerTemplate for key: " + key);
119+
if (!this._templateMap) {
120+
this._templateMap = new Map<string, KeyedTemplate>();
121+
}
122+
123+
const keyedTemplate = {
124+
key,
125+
createView: () => {
126+
listViewLog("registerTemplate for key: " + key);
127+
128+
const viewRef = this.loader.createEmbeddedView(template, new ListItemContext(), 0);
129+
const resultView = getSingleViewFromViewRef(viewRef);
130+
resultView[NG_VIEW] = viewRef;
131+
132+
return resultView;
133+
}
134+
};
135+
136+
this._templateMap.set(key, keyedTemplate);
137+
}
138+
94139
public onItemLoading(args) {
95-
if (!this.itemTemplate) {
140+
if (!args.view && !this.itemTemplate) {
96141
return;
97142
}
98143

@@ -115,6 +160,7 @@ export class ListViewComponent implements DoCheck, OnDestroy {
115160
args.view = getSingleViewFromViewRef(viewRef);
116161
args.view[NG_VIEW] = viewRef;
117162
}
163+
118164
this.setupViewRef(viewRef, currentItem, index);
119165

120166
this.detectChangesOnChild(viewRef, index);
@@ -128,7 +174,7 @@ export class ListViewComponent implements DoCheck, OnDestroy {
128174
context.$implicit = data;
129175
context.item = data;
130176
context.index = index;
131-
context.even = (index % 2 == 0);
177+
context.even = (index % 2 === 0);
132178
context.odd = !context.even;
133179

134180
this.setupItemView.next({ view: viewRef, data: data, index: index, context: context });
@@ -139,24 +185,23 @@ export class ListViewComponent implements DoCheck, OnDestroy {
139185
// TODO: Is there a better way of getting viewRef's change detector
140186
const childChangeDetector = <ChangeDetectorRef>(<any>viewRef);
141187

142-
listViewLog("Manually detect changes in child: " + index)
188+
listViewLog("Manually detect changes in child: " + index);
143189
childChangeDetector.markForCheck();
144190
childChangeDetector.detectChanges();
145191
}
146192

147193
ngDoCheck() {
148194
if (this._differ) {
149-
listViewLog("ngDoCheck() - execute differ")
195+
listViewLog("ngDoCheck() - execute differ");
150196
const changes = this._differ.diff(this._items);
151197
if (changes) {
152-
listViewLog("ngDoCheck() - refresh")
198+
listViewLog("ngDoCheck() - refresh");
153199
this.listView.refresh();
154200
}
155201
}
156202
}
157203
}
158204

159-
160205
function getSingleViewRecursive(nodes: Array<any>, nestLevel: number) {
161206
const actualNodes = nodes.filter((n) => !!n && n.nodeName !== "#text");
162207

@@ -175,7 +220,7 @@ function getSingleViewRecursive(nodes: Array<any>, nestLevel: number) {
175220
return actualNodes[0];
176221
}
177222
else {
178-
return getSingleViewRecursive(actualNodes[0].children, nestLevel + 1)
223+
return getSingleViewRecursive(actualNodes[0].children, nestLevel + 1);
179224
}
180225
}
181226
}
@@ -184,8 +229,24 @@ function getSingleViewFromViewRef(viewRef: EmbeddedViewRef<any>): View {
184229
return getSingleViewRecursive(viewRef.rootNodes, 0);
185230
}
186231

187-
const changeDetectorMode = ["CheckOnce", "Checked", "CheckAlways", "Detached", "OnPush", "Default"];
188-
const changeDetectorStates = ["Never", "CheckedBefore", "Error"];
189-
function getChangeDetectorState(cdr: any) {
190-
return "Mode: " + changeDetectorMode[parseInt(cdr.cdMode)] + " State: " + changeDetectorStates[parseInt(cdr.cdState)];
232+
@Directive({ selector: "[nsTemplateKey]" })
233+
export class TemplateKeyDirective {
234+
constructor(
235+
private templateRef: TemplateRef<any>,
236+
@Host() private list: ListViewComponent) {
237+
}
238+
239+
@Input()
240+
set nsTemplateKey(value: any) {
241+
if (this.list && this.templateRef) {
242+
this.list.registerTemplate(value, this.templateRef);
243+
}
244+
}
191245
}
246+
247+
// Debug helpers:
248+
// const changeDetectorMode = ["CheckOnce", "Checked", "CheckAlways", "Detached", "OnPush", "Default"];
249+
// const changeDetectorStates = ["Never", "CheckedBefore", "Error"];
250+
// function getChangeDetectorState(cdr: any) {
251+
// return "Mode: " + changeDetectorMode[parseInt(cdr.cdMode)] + " State: " + changeDetectorStates[parseInt(cdr.cdState)];
252+
// }

Diff for: nativescript-angular/router/page-router-outlet.ts

+11-11
Original file line numberDiff line numberDiff line change
@@ -111,18 +111,18 @@ export class PageRouterOutlet {
111111
deactivate(): void {
112112
if (this.locationStrategy._isPageNavigatingBack()) {
113113
log("PageRouterOutlet.deactivate() while going back - should destroy");
114-
const popedItem = this.refCache.pop();
115-
const popedRef = popedItem.componentRef;
114+
const poppedItem = this.refCache.pop();
115+
const poppedRef = poppedItem.componentRef;
116116

117-
if (this.currentActivatedComp !== popedRef) {
117+
if (this.currentActivatedComp !== poppedRef) {
118118
throw new Error("Current componentRef is different for cached componentRef");
119119
}
120120

121-
this.destroyCacheItem(popedItem);
121+
this.destroyCacheItem(poppedItem);
122122
this.currentActivatedComp = null;
123123

124124
} else {
125-
log("PageRouterOutlet.deactivate() while going foward - do nothing");
125+
log("PageRouterOutlet.deactivate() while going forward - do nothing");
126126
}
127127
}
128128

@@ -131,13 +131,13 @@ export class PageRouterOutlet {
131131
this.destroyCacheItem(this.refCache.pop());
132132
}
133133
}
134-
private destroyCacheItem(popedItem: CacheItem) {
135-
if (isPresent(popedItem.componentRef)) {
136-
popedItem.componentRef.destroy();
134+
private destroyCacheItem(poppedItem: CacheItem) {
135+
if (isPresent(poppedItem.componentRef)) {
136+
poppedItem.componentRef.destroy();
137137
}
138138

139-
if (isPresent(popedItem.loaderRef)) {
140-
popedItem.loaderRef.destroy();
139+
if (isPresent(poppedItem.loaderRef)) {
140+
poppedItem.loaderRef.destroy();
141141
}
142142
}
143143

@@ -206,7 +206,7 @@ export class PageRouterOutlet {
206206
this.outletMap = cacheItem.outletMap;
207207

208208
// HACK: Fill the outlet map provided by the router, with the outlets that we have cached.
209-
// This is needed beacuse the component is taken form the cache and not created - so it will not register
209+
// This is needed because the component is taken form the cache and not created - so it will not register
210210
// its child router-outlets to the newly created outlet map.
211211
(<any>Object).assign(outletMap, cacheItem.outletMap);
212212

Diff for: ng-sample/app/app.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@ import { Color } from "color";
2121
import trace = require("trace");
2222
// trace.setCategories(rendererTraceCategory);
2323
// trace.setCategories(routerTraceCategory);
24-
// trace.setCategories(listViewTraceCategory);
24+
trace.setCategories(listViewTraceCategory);
2525
trace.enable();
2626

2727
import { RendererTest } from './examples/renderer-test';
2828
import { TabViewTest } from './examples/tab-view/tab-view-test';
2929
import { Benchmark } from './performance/benchmark';
3030
import { ListTest } from './examples/list/list-test';
31+
import { ListTemplateSelectorTest } from './examples/list/template-selector';
3132
import { ListTestAsync, ListTestFilterAsync } from "./examples/list/list-test-async";
3233
import { ImageTest } from "./examples/image/image-test";
3334
import { HttpTest } from "./examples/http/http-test";
@@ -75,7 +76,7 @@ function makeExampleModule(componentType) {
7576
}
7677
let exports: any[] = [];
7778
if (componentType.exports) {
78-
exports = componentType.exports
79+
exports = componentType.exports;
7980
}
8081
let entries = [];
8182
if (componentType.entries) {
@@ -84,7 +85,7 @@ function makeExampleModule(componentType) {
8485
entries.push(componentType);
8586
let providers = [];
8687
if (componentType.providers) {
87-
providers = componentType.providers
88+
providers = componentType.providers;
8889
}
8990
@NgModule({
9091
bootstrap: [componentType],
@@ -112,10 +113,11 @@ const customPageFactoryProvider = {
112113
};
113114

114115
// platformNativeScriptDynamic().bootstrapModule(makeExampleModule(RendererTest));
115-
platformNativeScriptDynamic(undefined, [customPageFactoryProvider]).bootstrapModule(makeExampleModule(RendererTest));
116+
// platformNativeScriptDynamic(undefined, [customPageFactoryProvider]).bootstrapModule(makeExampleModule(RendererTest));
116117
//platformNativeScriptDynamic().bootstrapModule(makeExampleModule(TabViewTest));
117118
//platformNativeScriptDynamic().bootstrapModule(makeExampleModule(Benchmark));
118119
//platformNativeScriptDynamic().bootstrapModule(makeExampleModule(ListTest));
120+
platformNativeScriptDynamic().bootstrapModule(makeExampleModule(ListTemplateSelectorTest));
119121
//platformNativeScriptDynamic().bootstrapModule(makeExampleModule(ListTestAsync));
120122
//platformNativeScriptDynamic().bootstrapModule(makeExampleModule(ImageTest));
121123
// platformNativeScriptDynamic().bootstrapModule(makeExampleModule(ModalTest));

Diff for: ng-sample/app/examples/list/styles.css

+12
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,16 @@ button {
1313
.list-title {
1414
font-size: 20;
1515
text-align: center;
16+
}
17+
18+
.header {
19+
background-color: cornflowerblue;
20+
font-size: 28;
21+
color: black;
22+
text-align: center;
23+
}
24+
25+
.item {
26+
background-color: lightgreen;
27+
color: darkslategrey;
1628
}

0 commit comments

Comments
 (0)