Skip to content

Commit 40115ec

Browse files
committed
fix angular usage for ios
1 parent 818e8ca commit 40115ec

14 files changed

+8474
-4063
lines changed

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -214,28 +214,28 @@ export class AppModule { }
214214
</GridLayout>
215215
```
216216

217-
If you want to use multiple item templates, you can do that very similarly to how you do it for the builtin `ListView` control. The only difference is that due to current limitations instead of using the `nsTemplateKey` directive you need to use the `gvTemplateKey` directive that comes from the GridView. (In a future version, once the framework allows it this will be changed and you will be able to use the same directive for the `GridView` as well)
217+
If you want to use multiple item templates, you can do that very similarly to how you do it for the builtin `ListView` control.
218218
```html
219219
<GridView row="1" [items]="items" colWidth="33%" rowHeight="100" [itemTemplateSelector]="templateSelector">
220-
<ng-template gvTemplateKey="Defender" let-item="item" let-odd="odd">
220+
<ng-template nsTemplateKey="Defender" let-item="item" let-odd="odd">
221221
<StackLayout [nsRouterLink]="['/item', item.id]" borderColor="blue" borderWidth="2" borderRadius="5" verticalAlignment="stretch" class="list-group-item" [class.odd]="odd">
222222
<Label verticalAlignment="center" [text]="item.name" class="list-group-item-text" textWrap="true"></Label>
223223
</StackLayout>
224224
</ng-template>
225225

226-
<ng-template gvTemplateKey="Goalkeeper" let-item="item" let-odd="odd">
226+
<ng-template nsTemplateKey="Goalkeeper" let-item="item" let-odd="odd">
227227
<StackLayout [nsRouterLink]="['/item', item.id]" borderColor="black" borderWidth="2" borderRadius="5" verticalAlignment="stretch" class="list-group-item" [class.odd]="odd">
228228
<Label verticalAlignment="center" [text]="item.name" class="list-group-item-text" textWrap="true"></Label>
229229
</StackLayout>
230230
</ng-template>
231231

232-
<ng-template gvTemplateKey="Midfielder" let-item="item" let-odd="odd">
232+
<ng-template nsTemplateKey="Midfielder" let-item="item" let-odd="odd">
233233
<StackLayout [nsRouterLink]="['/item', item.id]" borderColor="yellow" borderWidth="2" borderRadius="5" verticalAlignment="stretch" class="list-group-item" [class.odd]="odd">
234234
<Label verticalAlignment="center" [text]="item.name" class="list-group-item-text" textWrap="true"></Label>
235235
</StackLayout>
236236
</ng-template>
237237

238-
<ng-template gvTemplateKey="Forward" let-item="item" let-odd="odd">
238+
<ng-template nsTemplateKey="Forward" let-item="item" let-odd="odd">
239239
<StackLayout [nsRouterLink]="['/item', item.id]" borderColor="red" borderWidth="2" borderRadius="5" verticalAlignment="stretch" class="list-group-item" [class.odd]="odd">
240240
<Label verticalAlignment="center" [text]="item.name" class="list-group-item-text" textWrap="true"></Label>
241241
</StackLayout>

angular/grid-view-comp.ts

Lines changed: 26 additions & 253 deletions
Original file line numberDiff line numberDiff line change
@@ -1,283 +1,56 @@
1-
/*
2-
Based on https://github.com/NativeScript/nativescript-angular/blob/3.1.0/nativescript-angular/directives/list-view-comp.ts
3-
Original License
4-
Copyright (c) 2015-2016 Telerik AD
1+
/*! *****************************************************************************
2+
Copyright (c) 2019 Tangra Inc.
53
6-
Licensed under the Apache License, Version 2.0 (the "License");
7-
you may not use this file except in compliance with the License.
8-
You may obtain a copy of the License at
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
97
10-
http://www.apache.org/licenses/LICENSE-2.0
8+
http://www.apache.org/licenses/LICENSE-2.0
119
12-
Unless required by applicable law or agreed to in writing, software
13-
distributed under the License is distributed on an "AS IS" BASIS,
14-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15-
See the License for the specific language governing permissions and
16-
limitations under the License.
17-
END - original License
18-
*/
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
***************************************************************************** */
1916

2017
import {
21-
AfterContentInit,
2218
ChangeDetectionStrategy,
2319
Component,
24-
ContentChild,
25-
Directive,
26-
DoCheck,
2720
ElementRef,
28-
EmbeddedViewRef,
29-
EventEmitter,
30-
Host,
31-
Inject,
32-
Input,
33-
IterableDiffer,
3421
IterableDiffers,
35-
OnDestroy,
36-
Output,
37-
TemplateRef,
38-
ViewChild,
39-
ViewContainerRef,
40-
ɵisListLikeIterable as isListLikeIterable,
22+
forwardRef
4123
} from "@angular/core";
42-
import { ObservableArray } from "tns-core-modules/data/observable-array";
43-
import { profile } from "tns-core-modules/profiling";
44-
import { KeyedTemplate, View } from "tns-core-modules/ui/core/view";
45-
import { LayoutBase } from "tns-core-modules/ui/layouts/layout-base";
46-
import { GridItemEventData, GridView } from "../grid-view";
47-
import { gridViewError, gridViewLog } from "./trace";
4824

49-
import { getSingleViewRecursive, isKnownView, registerElement } from "nativescript-angular/element-registry";
25+
import { TEMPLATED_ITEMS_COMPONENT, TemplatedItemsComponent } from "nativescript-angular/directives/templated-items-comp";
26+
import { isKnownView, registerElement } from "nativescript-angular/element-registry";
5027

51-
const NG_VIEW = "_ngViewRef";
52-
53-
export class GridItemContext {
54-
constructor(
55-
public $implicit?: any,
56-
public item?: any,
57-
public index?: number,
58-
public even?: boolean,
59-
public odd?: boolean
60-
) {
61-
}
62-
}
63-
64-
export interface SetupItemViewArgs {
65-
view: EmbeddedViewRef<any>;
66-
data: any;
67-
index: number;
68-
context: GridItemContext;
69-
}
28+
import { GridView } from "../grid-view";
7029

7130
@Component({
7231
selector: "GridView",
7332
template: `
7433
<DetachedContainer>
7534
<Placeholder #loader></Placeholder>
7635
</DetachedContainer>`,
77-
changeDetection: ChangeDetectionStrategy.OnPush
36+
changeDetection: ChangeDetectionStrategy.OnPush,
37+
providers: [{ provide: TEMPLATED_ITEMS_COMPONENT, useExisting: forwardRef(() => GridViewComponent)}]
7838
})
79-
export class GridViewComponent implements DoCheck, OnDestroy, AfterContentInit {
39+
export class GridViewComponent extends TemplatedItemsComponent {
8040
public get nativeElement(): GridView {
81-
return this.gridView;
82-
}
83-
84-
@ViewChild("loader", { read: ViewContainerRef }) public loader: ViewContainerRef;
85-
@Output() public setupItemView = new EventEmitter<SetupItemViewArgs>();
86-
@ContentChild(TemplateRef) public itemTemplateQuery: TemplateRef<GridItemContext>;
87-
88-
@Input()
89-
public get items() {
90-
return this._items;
91-
}
92-
public set items(value: any) {
93-
this._items = value;
94-
let needDiffer = true;
95-
if (value instanceof ObservableArray) {
96-
needDiffer = false;
97-
}
98-
if (needDiffer && !this._differ && isListLikeIterable(value)) {
99-
this._differ = this._iterableDiffers.find(this._items)
100-
.create((_index, item) => item);
101-
}
102-
103-
this.gridView.items = this._items;
41+
return this.templatedItemsView;
10442
}
10543

106-
private gridView: GridView;
107-
private _items: any;
108-
private _differ: IterableDiffer<KeyedTemplate>;
109-
private itemTemplate: TemplateRef<GridItemContext>;
110-
private _templateMap: Map<string, KeyedTemplate>;
44+
protected templatedItemsView: GridView;
11145

11246
constructor(
113-
@Inject(ElementRef) _elementRef: ElementRef,
114-
@Inject(IterableDiffers) private _iterableDiffers: IterableDiffers,
115-
) {
116-
this.gridView = _elementRef.nativeElement;
117-
118-
this.gridView.on(GridView.itemLoadingEvent, this.onItemLoading, this);
119-
}
120-
121-
public ngAfterContentInit() {
122-
gridViewLog("GridView.ngAfterContentInit()");
123-
this.setItemTemplates();
124-
}
125-
126-
public ngOnDestroy() {
127-
this.gridView.off(GridView.itemLoadingEvent, this.onItemLoading, this);
128-
}
129-
130-
public ngDoCheck() {
131-
gridViewLog("ngDoCheck() - execute differ? " + this._differ);
132-
if (this._differ) {
133-
gridViewLog("ngDoCheck() - execute differ");
134-
const changes = this._differ.diff(this._items);
135-
if (changes) {
136-
gridViewLog("ngDoCheck() - refresh");
137-
this.refresh();
138-
}
139-
}
140-
}
141-
142-
public registerTemplate(key: string, template: TemplateRef<GridItemContext>) {
143-
gridViewLog("registerTemplate for key: " + key);
144-
if (!this._templateMap) {
145-
this._templateMap = new Map<string, KeyedTemplate>();
146-
}
147-
148-
const keyedTemplate = {
149-
key,
150-
createView: this.createNativeViewFactoryFromTemplate(template),
151-
};
152-
153-
this._templateMap.set(key, keyedTemplate);
154-
}
155-
156-
@profile
157-
public onItemLoading(args: GridItemEventData) {
158-
if (!args.view && !this.itemTemplate) {
159-
return;
160-
}
161-
162-
const index = args.index;
163-
const items = args.object.items as any;
164-
const currentItem = typeof items.getItem === "function" ? items.getItem(index) : items[index];
165-
let viewRef: EmbeddedViewRef<GridItemContext>;
166-
167-
if (args.view) {
168-
gridViewLog("onItemLoading: " + index + " - Reusing existing view");
169-
viewRef = args.view[NG_VIEW];
170-
// Getting angular view from original element (in cases when ProxyViewContainer
171-
// is used NativeScript internally wraps it in a StackLayout)
172-
if (!viewRef && args.view instanceof LayoutBase && args.view.getChildrenCount() > 0) {
173-
viewRef = args.view.getChildAt(0)[NG_VIEW];
174-
}
175-
176-
if (!viewRef) {
177-
gridViewError("ViewReference not found for item " + index + ". View recycling is not working");
178-
}
179-
}
180-
181-
if (!viewRef) {
182-
gridViewLog("onItemLoading: " + index + " - Creating view from template");
183-
viewRef = this.loader.createEmbeddedView(this.itemTemplate, new GridItemContext(), 0);
184-
args.view = getItemViewRoot(viewRef);
185-
args.view[NG_VIEW] = viewRef;
186-
}
187-
188-
this.setupViewRef(viewRef, currentItem, index);
189-
190-
this.detectChangesOnChild(viewRef, index);
191-
}
192-
193-
public setupViewRef(view: EmbeddedViewRef<GridItemContext>, data: any, index: number): void {
194-
const context = view.context;
195-
context.$implicit = data;
196-
context.item = data;
197-
context.index = index;
198-
context.even = (index % 2 === 0);
199-
context.odd = !context.even;
200-
201-
this.setupItemView.next({
202-
context,
203-
data,
204-
index,
205-
view,
206-
});
207-
}
208-
209-
private createNativeViewFactoryFromTemplate(template: TemplateRef<GridItemContext>) {
210-
return () => {
211-
const viewRef = this.loader.createEmbeddedView(template, new GridItemContext(), 0);
212-
const resultView = getItemViewRoot(viewRef);
213-
resultView[NG_VIEW] = viewRef;
214-
215-
return resultView;
216-
};
217-
}
218-
219-
private setItemTemplates() {
220-
// The itemTemplateQuery may be changed after list items are added that contain <template> inside,
221-
// so cache and use only the original template to avoid errors.
222-
this.itemTemplate = this.itemTemplateQuery;
223-
224-
if (this._templateMap) {
225-
gridViewLog("Setting templates");
226-
227-
const templates: KeyedTemplate[] = [];
228-
this._templateMap.forEach((value) => {
229-
templates.push(value);
230-
});
231-
this.gridView.itemTemplates = templates;
232-
}
233-
else { // If the map was not initialized this means that there are no named templates, so we register the default one.
234-
this.gridView.itemTemplate = this.createNativeViewFactoryFromTemplate(this.itemTemplate);
235-
}
236-
}
237-
238-
@profile
239-
private detectChangesOnChild(viewRef: EmbeddedViewRef<GridItemContext>, index: number) {
240-
gridViewLog("Manually detect changes in child: " + index);
241-
viewRef.markForCheck();
242-
viewRef.detectChanges();
243-
}
244-
245-
private refresh() {
246-
if (this.gridView) {
247-
this.gridView.refresh();
248-
}
249-
}
250-
}
251-
252-
export interface ComponentView {
253-
rootNodes: any[];
254-
destroy(): void;
255-
}
256-
257-
export type RootLocator = (nodes: any[], nestLevel: number) => View;
258-
259-
export function getItemViewRoot(viewRef: ComponentView, rootLocator: RootLocator = getSingleViewRecursive): View {
260-
const rootView = rootLocator(viewRef.rootNodes, 0);
261-
return rootView;
262-
}
263-
264-
@Directive({ selector: "[gvTemplateKey]" })
265-
export class TemplateKeyDirective {
266-
constructor(
267-
private templateRef: TemplateRef<any>,
268-
@Host() private grid: GridViewComponent,
269-
) {
270-
}
271-
272-
@Input()
273-
set gvTemplateKey(value: any) {
274-
gridViewLog("gvTemplateKey: " + value);
275-
if (this.grid && this.templateRef) {
276-
this.grid.registerTemplate(value, this.templateRef);
277-
}
47+
_elementRef: ElementRef,
48+
_iterableDiffers: IterableDiffers) {
49+
super(_elementRef, _iterableDiffers);
50+
27851
}
27952
}
28053

28154
if (!isKnownView("GridView")) {
282-
registerElement("GridView", () => GridView);
55+
registerElement("GridView", () => GridView);
28356
}

angular/index.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,14 @@ import {
44
NgModule,
55
} from "@angular/core";
66

7-
import { GridViewComponent, TemplateKeyDirective } from "./grid-view-comp";
7+
import { GridViewComponent } from "./grid-view-comp";
88

99
@NgModule({
1010
declarations: [
1111
GridViewComponent,
12-
TemplateKeyDirective,
1312
],
1413
exports: [
1514
GridViewComponent,
16-
TemplateKeyDirective,
1715
],
1816
schemas: [
1917
NO_ERRORS_SCHEMA,

demo-ng/app/item/items.component.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,25 @@
3232
</ng-template>
3333
</GridView>
3434
<GridView row="1" [items]="items" colWidth="33%" rowHeight="100" orientation="horizontal" [itemTemplateSelector]="templateSelector">
35-
<ng-template gvTemplateKey="Defender" let-item="item" let-odd="odd">
35+
<ng-template nsTemplateKey="Defender" let-item="item" let-odd="odd">
3636
<StackLayout [nsRouterLink]="['/item', item.id]" borderColor="blue" borderWidth="2" borderRadius="5" verticalAlignment="stretch" class="list-group-item" [class.odd]="odd">
3737
<Label verticalAlignment="center" [text]="item.name" class="list-group-item-text" textWrap="true"></Label>
3838
</StackLayout>
3939
</ng-template>
4040

41-
<ng-template gvTemplateKey="Goalkeeper" let-item="item" let-odd="odd">
41+
<ng-template nsTemplateKey="Goalkeeper" let-item="item" let-odd="odd">
4242
<StackLayout [nsRouterLink]="['/item', item.id]" borderColor="black" borderWidth="2" borderRadius="5" verticalAlignment="stretch" class="list-group-item" [class.odd]="odd">
4343
<Label verticalAlignment="center" [text]="item.name" class="list-group-item-text" textWrap="true"></Label>
4444
</StackLayout>
4545
</ng-template>
4646

47-
<ng-template gvTemplateKey="Midfielder" let-item="item" let-odd="odd">
47+
<ng-template nsTemplateKey="Midfielder" let-item="item" let-odd="odd">
4848
<StackLayout [nsRouterLink]="['/item', item.id]" borderColor="yellow" borderWidth="2" borderRadius="5" verticalAlignment="stretch" class="list-group-item" [class.odd]="odd">
4949
<Label verticalAlignment="center" [text]="item.name" class="list-group-item-text" textWrap="true"></Label>
5050
</StackLayout>
5151
</ng-template>
5252

53-
<ng-template gvTemplateKey="Forward" let-item="item" let-odd="odd">
53+
<ng-template nsTemplateKey="Forward" let-item="item" let-odd="odd">
5454
<StackLayout [nsRouterLink]="['/item', item.id]" borderColor="red" borderWidth="2" borderRadius="5" verticalAlignment="stretch" class="list-group-item" [class.odd]="odd">
5555
<Label verticalAlignment="center" [text]="item.name" class="list-group-item-text" textWrap="true"></Label>
5656
</StackLayout>

0 commit comments

Comments
 (0)