Skip to content

Commit 63534a2

Browse files
author
vakrilov
committed
List View template selector
1 parent f8a56f3 commit 63534a2

File tree

8 files changed

+218
-57
lines changed

8 files changed

+218
-57
lines changed

nativescript-angular/directives.ts

Lines changed: 15 additions & 14 deletions
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';

nativescript-angular/directives/list-view-comp.ts

Lines changed: 82 additions & 21 deletions
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+
// }

nativescript-angular/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
"url": "0.10.3"
3838
},
3939
"devDependencies": {
40-
"tns-core-modules": ">=2.2.0 || >=2.2.0-2016",
40+
"tns-core-modules": ">=2.4.0 || >=2.4.0-2016",
4141
"zone.js": "^0.6.21",
4242
"typescript": "^2.0.2",
4343
"@angular/compiler-cli": "~2.1.1"

nativescript-angular/router/page-router-outlet.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class RefCache {
6060
export class PageRouterOutlet {
6161
private viewUtil: ViewUtil;
6262
private refCache: RefCache = new RefCache();
63-
private isInitalPage: boolean = true;
63+
private isInitialPage: boolean = true;
6464
private detachedLoaderFactory: ComponentFactory<DetachedLoader>;
6565

6666
private currentActivatedComp: ComponentRef<any>;
@@ -108,18 +108,18 @@ export class PageRouterOutlet {
108108
deactivate(): void {
109109
if (this.locationStrategy._isPageNavigatingBack()) {
110110
log("PageRouterOutlet.deactivate() while going back - should destroy");
111-
const popedItem = this.refCache.pop();
112-
const popedRef = popedItem.componentRef;
111+
const poppedItem = this.refCache.pop();
112+
const poppedRef = poppedItem.componentRef;
113113

114-
if (this.currentActivatedComp !== popedRef) {
114+
if (this.currentActivatedComp !== poppedRef) {
115115
throw new Error("Current componentRef is different for cached componentRef");
116116
}
117117

118-
this.destroyCacheItem(popedItem);
118+
this.destroyCacheItem(poppedItem);
119119
this.currentActivatedComp = null;
120120

121121
} else {
122-
log("PageRouterOutlet.deactivate() while going foward - do nothing");
122+
log("PageRouterOutlet.deactivate() while going forward - do nothing");
123123
}
124124
}
125125

@@ -128,13 +128,13 @@ export class PageRouterOutlet {
128128
this.destroyCacheItem(this.refCache.pop());
129129
}
130130
}
131-
private destroyCacheItem(popedItem: CacheItem) {
132-
if (isPresent(popedItem.componentRef)) {
133-
popedItem.componentRef.destroy();
131+
private destroyCacheItem(poppedItem: CacheItem) {
132+
if (isPresent(poppedItem.componentRef)) {
133+
poppedItem.componentRef.destroy();
134134
}
135135

136-
if (isPresent(popedItem.loaderRef)) {
137-
popedItem.loaderRef.destroy();
136+
if (isPresent(poppedItem.loaderRef)) {
137+
poppedItem.loaderRef.destroy();
138138
}
139139
}
140140

@@ -165,9 +165,9 @@ export class PageRouterOutlet {
165165
const pageRoute = new PageRoute(activatedRoute);
166166
providers = [...providers, ...ReflectiveInjector.resolve([{ provide: PageRoute, useValue: pageRoute }])];
167167

168-
if (this.isInitalPage) {
169-
log("PageRouterOutlet.activate() inital page - just load component");
170-
this.isInitalPage = false;
168+
if (this.isInitialPage) {
169+
log("PageRouterOutlet.activate() initial page - just load component");
170+
this.isInitialPage = false;
171171
const inj = ReflectiveInjector.fromResolvedProviders(providers, this.containerRef.parentInjector);
172172
this.currentActivatedComp = this.containerRef.createComponent(factory, this.containerRef.length, inj, []);
173173
this.refCache.push(this.currentActivatedComp, pageRoute, outletMap, null);
@@ -192,7 +192,7 @@ export class PageRouterOutlet {
192192
activatedRoute: ActivatedRoute,
193193
providers: ResolvedReflectiveProvider[],
194194
outletMap: RouterOutletMap): void {
195-
log("PageRouterOutlet.activate() - Back naviation, so load from cache");
195+
log("PageRouterOutlet.activate() - Back navigation, so load from cache");
196196

197197
this.locationStrategy._finishBackPageNavigation();
198198

@@ -202,7 +202,7 @@ export class PageRouterOutlet {
202202
this.outletMap = cacheItem.outletMap;
203203

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

ng-sample/app/app.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ import { Color } from "color";
2020
import trace = require("trace");
2121
// trace.setCategories(rendererTraceCategory);
2222
// trace.setCategories(routerTraceCategory);
23-
// trace.setCategories(listViewTraceCategory);
23+
trace.setCategories(listViewTraceCategory);
2424
trace.enable();
2525

2626
import { RendererTest } from './examples/renderer-test';
2727
import { TabViewTest } from './examples/tab-view/tab-view-test';
2828
import { Benchmark } from './performance/benchmark';
2929
import { ListTest } from './examples/list/list-test';
30+
import { ListTemplateSelectorTest } from './examples/list/template-selector';
3031
import { ListTestAsync, ListTestFilterAsync } from "./examples/list/list-test-async";
3132
import { ImageTest } from "./examples/image/image-test";
3233
import { HttpTest } from "./examples/http/http-test";
@@ -74,7 +75,7 @@ function makeExampleModule(componentType) {
7475
}
7576
let exports: any[] = [];
7677
if (componentType.exports) {
77-
exports = componentType.exports
78+
exports = componentType.exports;
7879
}
7980
let entries = [];
8081
if (componentType.entries) {
@@ -83,7 +84,7 @@ function makeExampleModule(componentType) {
8384
entries.push(componentType);
8485
let providers = [];
8586
if (componentType.providers) {
86-
providers = componentType.providers
87+
providers = componentType.providers;
8788
}
8889
@NgModule({
8990
bootstrap: [componentType],
@@ -111,10 +112,11 @@ const customPageFactoryProvider = {
111112
};
112113

113114
// platformNativeScriptDynamic().bootstrapModule(makeExampleModule(RendererTest));
114-
platformNativeScriptDynamic(undefined, [customPageFactoryProvider]).bootstrapModule(makeExampleModule(RendererTest));
115+
// platformNativeScriptDynamic(undefined, [customPageFactoryProvider]).bootstrapModule(makeExampleModule(RendererTest));
115116
//platformNativeScriptDynamic().bootstrapModule(makeExampleModule(TabViewTest));
116117
//platformNativeScriptDynamic().bootstrapModule(makeExampleModule(Benchmark));
117118
//platformNativeScriptDynamic().bootstrapModule(makeExampleModule(ListTest));
119+
platformNativeScriptDynamic().bootstrapModule(makeExampleModule(ListTemplateSelectorTest));
118120
//platformNativeScriptDynamic().bootstrapModule(makeExampleModule(ListTestAsync));
119121
//platformNativeScriptDynamic().bootstrapModule(makeExampleModule(ImageTest));
120122
// platformNativeScriptDynamic().bootstrapModule(makeExampleModule(ModalTest));

ng-sample/app/examples/list/styles.css

Lines changed: 12 additions & 0 deletions
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)