Skip to content

Commit 7a86de7

Browse files
committed
refactor(renderer): create DetachedElements instead for comments and
text nodes
1 parent f1d9e05 commit 7a86de7

File tree

6 files changed

+72
-74
lines changed

6 files changed

+72
-74
lines changed

Diff for: nativescript-angular/directives/action-bar.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { registerElement, ViewClassMeta, NgView } from "../element-registry";
77

88
const actionBarMeta: ViewClassMeta = {
99
skipAddToDom: true,
10-
insertChild: (parent: NgView, child: NgView, atIndex: number) => {
10+
insertChild: (parent: NgView, child: NgView) => {
1111
const bar = <ActionBar>(<any>parent);
1212
const childView = <any>child;
1313

@@ -17,8 +17,6 @@ const actionBarMeta: ViewClassMeta = {
1717
} else if (child instanceof ActionItem) {
1818
bar.actionItems.addItem(childView);
1919
childView.parent = bar;
20-
} else if (child.nodeName === "#comment") {
21-
bar._addView(childView, atIndex);
2220
} else if (child instanceof View) {
2321
bar.titleView = childView;
2422
}

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

+32-26
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,31 @@
11
import {
2+
AfterContentInit,
3+
ChangeDetectionStrategy,
4+
ChangeDetectorRef,
25
Component,
6+
ContentChild,
37
Directive,
4-
Input,
58
DoCheck,
6-
OnDestroy,
7-
AfterContentInit,
89
ElementRef,
9-
ViewContainerRef,
10-
TemplateRef,
11-
ContentChild,
1210
EmbeddedViewRef,
13-
IterableDiffers,
14-
IterableDiffer,
15-
ChangeDetectorRef,
1611
EventEmitter,
17-
ViewChild,
18-
Output,
1912
Host,
20-
ChangeDetectionStrategy
13+
Input,
14+
IterableDiffer,
15+
IterableDiffers,
16+
OnDestroy,
17+
Output,
18+
TemplateRef,
19+
ViewChild,
20+
ViewContainerRef,
2121
} from "@angular/core";
22-
import { isListLikeIterable } from "../collection-facade";
2322
import { ListView, ItemEventData } from "tns-core-modules/ui/list-view";
2423
import { View, KeyedTemplate } from "tns-core-modules/ui/core/view";
2524
import { ObservableArray } from "tns-core-modules/data/observable-array";
2625
import { LayoutBase } from "tns-core-modules/ui/layouts/layout-base";
26+
27+
import { DetachedElement } from "../element-registry";
28+
import { isListLikeIterable } from "../collection-facade";
2729
import { listViewLog, listViewError } from "../trace";
2830

2931
const NG_VIEW = "_ngViewRef";
@@ -212,23 +214,27 @@ export class ListViewComponent implements DoCheck, OnDestroy, AfterContentInit {
212214
}
213215

214216
function getSingleViewRecursive(nodes: Array<any>, nestLevel: number): View {
215-
const actualNodes = nodes.filter((n) => !!n && n.nodeName !== "#text");
217+
const actualNodes = nodes.filter(node => !(node instanceof DetachedElement));
216218

217219
if (actualNodes.length === 0) {
218-
throw new Error("No suitable views found in list template! Nesting level: " + nestLevel);
220+
throw new Error(`No suitable views found in list template! ` +
221+
`Nesting level: ${nestLevel}`);
219222
} else if (actualNodes.length > 1) {
220-
throw new Error("More than one view found in list template! Nesting level: " + nestLevel);
221-
} else {
222-
if (actualNodes[0]) {
223-
let parentLayout = actualNodes[0].parent;
224-
if (parentLayout instanceof LayoutBase) {
225-
parentLayout.removeChild(actualNodes[0]);
226-
}
227-
return actualNodes[0];
228-
} else {
229-
return getSingleViewRecursive(actualNodes[0].children, nestLevel + 1);
230-
}
223+
throw new Error(`More than one view found in list template!` +
224+
`Nesting level: ${nestLevel}`);
225+
}
226+
227+
const rootLayout = actualNodes[0];
228+
if (!rootLayout) {
229+
return getSingleViewRecursive(rootLayout.children, nestLevel + 1);
230+
}
231+
232+
let parentLayout = rootLayout.parent;
233+
if (parentLayout instanceof LayoutBase) {
234+
parentLayout.removeChild(rootLayout);
231235
}
236+
237+
return rootLayout;
232238
}
233239

234240
export interface ComponentView {

Diff for: nativescript-angular/directives/tab-view.ts

+14-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
1-
import { ElementRef, Directive, Input, TemplateRef, ViewContainerRef, OnInit, AfterViewInit } from "@angular/core";
1+
import {
2+
AfterViewInit,
3+
Directive,
4+
ElementRef,
5+
Input,
6+
OnInit,
7+
TemplateRef,
8+
ViewContainerRef,
9+
} from "@angular/core";
210
import { TabView, TabViewItem } from "tns-core-modules/ui/tab-view";
11+
12+
import { DetachedElement } from "../element-registry";
313
import { convertToInt } from "../common/utils";
414
import { rendererLog } from "../trace";
515
import { isBlank } from "../lang-facade";
@@ -94,9 +104,9 @@ export class TabViewItemDirective implements OnInit {
94104
}
95105

96106
const viewRef = this.viewContainer.createEmbeddedView(this.templateRef);
97-
// Filter out text nodes, etc
98-
const realViews = viewRef.rootNodes.filter((node) =>
99-
node.nodeName && node.nodeName !== "#text");
107+
// Filter out text nodes and comments
108+
const realViews = viewRef.rootNodes.filter(node =>
109+
!(node instanceof DetachedElement));
100110

101111
if (realViews.length > 0) {
102112
this.item.view = realViews[0];

Diff for: nativescript-angular/element-registry.ts

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { View } from "tns-core-modules/ui/core/view";
22

33
export type ViewResolver = () => ViewClass;
4-
export type NgView = View & ViewExtensions;
4+
export type NgView = (View & ViewExtensions);
5+
export type NgElement = NgView | DetachedElement;
56
export interface ViewClassMeta {
67
skipAddToDom?: boolean;
78
insertChild?: (parent: NgView, child: NgView, atIndex: number) => void;
@@ -20,6 +21,11 @@ export interface ViewClass {
2021
new (): View;
2122
}
2223

24+
export class DetachedElement {
25+
templateParent: NgView;
26+
meta: { skipAddToDom: true };
27+
}
28+
2329
const defaultViewMeta: ViewClassMeta = {
2430
skipAddToDom: false,
2531
};
@@ -110,10 +116,3 @@ registerElement("Span", () => require("tns-core-modules/text/span").Span);
110116

111117
registerElement("DetachedContainer", () => require("tns-core-modules/ui/proxy-view-container").ProxyViewContainer,
112118
{ skipAddToDom: true });
113-
114-
registerElement("DetachedText", () => require("ui/placeholder").Placeholder,
115-
{ skipAddToDom: true });
116-
117-
registerElement("Comment", () => require("ui/placeholder").Placeholder,
118-
{ skipAddToDom: true });
119-

Diff for: nativescript-angular/renderer.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { topmost } from "tns-core-modules/ui/frame";
1212
import { APP_ROOT_VIEW, DEVICE, getRootPage } from "./platform-providers";
1313
import { isBlank } from "./lang-facade";
1414
import { ViewUtil } from "./view-util";
15-
import { NgView } from "./element-registry";
15+
import { NgView, DetachedElement } from "./element-registry";
1616
import { rendererLog as traceLog } from "./trace";
1717

1818
// CONTENT_ATTR not exported from NativeScript_renderer - we need it for styles application.
@@ -111,7 +111,7 @@ export class NativeScriptRenderer extends Renderer2 {
111111
return this.viewUtil.nextSiblingIndex(node);
112112
}
113113

114-
createComment(_value: any) {
114+
createComment(_value: any): DetachedElement {
115115
traceLog(`NativeScriptRenderer.createComment ${_value}`);
116116
return this.viewUtil.createComment();
117117
}
@@ -121,7 +121,7 @@ export class NativeScriptRenderer extends Renderer2 {
121121
return this.viewUtil.createView(name);
122122
}
123123

124-
createText(_value: string) {
124+
createText(_value: string): DetachedElement {
125125
traceLog(`NativeScriptRenderer.createText ${_value}`);
126126
return this.viewUtil.createText();
127127
}

Diff for: nativescript-angular/view-util.ts

+15-30
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88
getViewMeta,
99
isKnownView,
1010
ViewExtensions,
11+
DetachedElement,
12+
NgElement,
1113
NgView,
1214
} from "./element-registry";
1315
import { platformNames, Device } from "tns-core-modules/platform";
@@ -47,21 +49,21 @@ export class ViewUtil {
4749
this.isAndroid = device.os === platformNames.android;
4850
}
4951

50-
public insertChild(parent: any, child: NgView, atIndex: number = -1) {
51-
if (!parent) {
52+
public insertChild(parent: any, child: NgElement, atIndex: number = -1) {
53+
if (child instanceof DetachedElement) {
54+
child.templateParent = parent;
5255
return;
5356
}
5457

55-
if (child.meta.skipAddToDom) {
56-
child.templateParent = parent;
58+
if (!parent || child.meta.skipAddToDom) {
5759
return;
5860
}
5961

6062
if (parent.meta && parent.meta.insertChild) {
6163
parent.meta.insertChild(parent, child, atIndex);
6264
} else if (isLayout(parent)) {
6365
if (child.parent === parent) {
64-
let index = (<LayoutBase>parent).getChildIndex(child);
66+
const index = (<LayoutBase>parent).getChildIndex(child);
6567
if (index !== -1) {
6668
parent.removeChild(child);
6769
}
@@ -72,21 +74,16 @@ export class ViewUtil {
7274
parent.addChild(child);
7375
}
7476
} else if (isContentView(parent)) {
75-
// Explicit handling of template anchors inside ContentView
76-
if (child.nodeName === "#comment") {
77-
parent._addView(child, atIndex);
78-
} else {
79-
parent.content = child;
80-
}
77+
parent.content = child;
8178
} else if (parent && parent._addChildFromBuilder) {
8279
parent._addChildFromBuilder(child.nodeName, child);
8380
} else {
8481
// throw new Error("Parent can"t contain children: " + parent.nodeName + ", " + parent);
8582
}
8683
}
8784

88-
public removeChild(parent: any, child: NgView) {
89-
if (!parent || child.meta.skipAddToDom) {
85+
public removeChild(parent: any, child: NgElement) {
86+
if (!parent || child instanceof DetachedElement || child.meta.skipAddToDom) {
9087
return;
9188
}
9289

@@ -98,11 +95,6 @@ export class ViewUtil {
9895
if (parent.content === child) {
9996
parent.content = null;
10097
}
101-
102-
// Explicit handling of template anchors inside ContentView
103-
if (child.nodeName === "#comment") {
104-
parent._removeView(child);
105-
}
10698
} else if (isView(parent)) {
10799
parent._removeView(child);
108100
} else {
@@ -120,20 +112,12 @@ export class ViewUtil {
120112
}
121113
}
122114

123-
public createComment(): NgView {
124-
const commentView = this.createView("Comment");
125-
commentView.nodeName = "#comment";
126-
commentView.visibility = "collapse";
127-
128-
return commentView;
115+
public createComment(): DetachedElement {
116+
return new DetachedElement();
129117
}
130118

131-
public createText(): NgView {
132-
const detachedText = this.createView("DetachedText");
133-
detachedText.nodeName = "#text";
134-
detachedText.visibility = "collapse";
135-
136-
return detachedText;
119+
public createText(): DetachedElement {
120+
return new DetachedElement();
137121
}
138122

139123
public createView(name: string): NgView {
@@ -142,6 +126,7 @@ export class ViewUtil {
142126
if (!isKnownView(name)) {
143127
name = "ProxyViewContainer";
144128
}
129+
145130
const viewClass = getViewClass(name);
146131
let view = <NgView>new viewClass();
147132
view.nodeName = name;

0 commit comments

Comments
 (0)