Skip to content

Commit b82e64a

Browse files
author
Vladimir Enchev
committed
Merge pull request NativeScript#318 from NativeScript/custom-components-in-templates
support for custom components in templates + tests
2 parents 42e6baa + 53f3a32 commit b82e64a

File tree

4 files changed

+77
-29
lines changed

4 files changed

+77
-29
lines changed

apps/tests/xml-declaration/xml-declaration-tests.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import observable = require("data/observable");
1313
import stackLayoutModule = require("ui/layouts/stack-layout");
1414
import labelModule = require("ui/label");
1515
import myCustomControlWithoutXml = require("./mymodule/MyControl");
16+
import listViewModule = require("ui/list-view");
17+
import helper = require("../ui/helper");
18+
import viewModule = require("ui/core/view");
1619

1720
export var test_load_IsDefined = function () {
1821
TKUnit.assert(types.isFunction(builder.load), "ui/builder should have load method!");
@@ -179,3 +182,31 @@ export var test_parse_ShouldParseCustomComponentWitXmlWithAttributes = function
179182

180183
TKUnit.assert(panel.visibility === "collapsed", "Expected result: 'collapsed'; Actual result: " + panel.visibility);
181184
};
185+
186+
export function test_parse_ShouldParseCustomComponentWithoutXmlInListViewTemplate() {
187+
var p = <page.Page>builder.parse('<Page xmlns:customControls="xml-declaration/mymodule"><ListView items="{{ items }}" itemLoading="{{ itemLoading }}"><ListView.itemTemplate><customControls:MyControl /></ListView.itemTemplate></ListView></Page>');
188+
189+
function testAction(views: Array<viewModule.View>) {
190+
var ctrl;
191+
192+
var obj = new observable.Observable();
193+
obj.set("items", [1]);
194+
obj.set("itemLoading", function (args: listViewModule.ItemEventData) {
195+
ctrl = args.view
196+
});
197+
p.bindingContext = obj;
198+
199+
TKUnit.wait(0.2);
200+
201+
TKUnit.assert(ctrl instanceof myCustomControlWithoutXml.MyControl, "Expected result: custom control is defined!; Actual result: " + ctrl);
202+
};
203+
204+
helper.navigate(function () { return p; });
205+
206+
try {
207+
testAction([p.content, p]);
208+
}
209+
finally {
210+
helper.goBack();
211+
}
212+
}

ui/builder/builder.ts

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ function parseInternal(value: string, exports: any): componentBuilder.ComponentM
3232

3333
if (templateBuilder) {
3434
if (args.eventType === xml.ParserEventType.StartElement) {
35-
templateBuilder.addStartElement(args.elementName, args.attributes);
35+
templateBuilder.addStartElement(args.prefix, args.namespace, args.elementName, args.attributes);
3636
} else if (args.eventType === xml.ParserEventType.EndElement) {
3737
if (templateBuilder.elementName !== args.elementName) {
38-
templateBuilder.addEndElement(args.elementName);
38+
templateBuilder.addEndElement(args.prefix, args.elementName);
3939
} else {
4040
templateBuilder.build();
4141
templateBuilder = undefined;
@@ -72,35 +72,40 @@ function parseInternal(value: string, exports: any): componentBuilder.ComponentM
7272

7373
var componentModule: componentBuilder.ComponentModule;
7474

75-
if (args.namespace) {
75+
if (args.prefix) {
7676
// Custom components
77-
var xmlPath = fs.path.join(fs.knownFolders.currentApp().path, args.namespace, args.elementName) + ".xml";
78-
if (fs.File.exists(xmlPath)) {
79-
// Custom components with XML
80-
var jsPath = xmlPath.replace(".xml", ".js");
81-
var subExports;
82-
if (fs.File.exists(jsPath)) {
83-
// Custom components with XML and code
84-
subExports = require(jsPath.replace(".js", ""))
85-
}
8677

87-
componentModule = loadInternal(xmlPath, subExports);
78+
var ns = args.namespace;
79+
80+
if (ns) {
81+
var xmlPath = fs.path.join(fs.knownFolders.currentApp().path, ns, args.elementName) + ".xml";
8882

89-
// Attributes will be transfered to the custom component
90-
if (types.isDefined(componentModule) && types.isDefined(componentModule.component)) {
91-
var attr: string;
92-
for (attr in args.attributes) {
93-
componentBuilder.setPropertyValue(componentModule.component, subExports, exports, attr, args.attributes[attr]);
83+
if (fs.File.exists(xmlPath)) {
84+
// Custom components with XML
85+
var jsPath = xmlPath.replace(".xml", ".js");
86+
var subExports;
87+
if (fs.File.exists(jsPath)) {
88+
// Custom components with XML and code
89+
subExports = require(jsPath.replace(".js", ""))
9490
}
95-
}
9691

97-
} else {
98-
// Custom components without XML
99-
componentModule = componentBuilder.getComponentModule(args.elementName, args.namespace, args.attributes, exports);
92+
componentModule = loadInternal(xmlPath, subExports);
93+
94+
// Attributes will be transfered to the custom component
95+
if (types.isDefined(componentModule) && types.isDefined(componentModule.component)) {
96+
var attr: string;
97+
for (attr in args.attributes) {
98+
componentBuilder.setPropertyValue(componentModule.component, subExports, exports, attr, args.attributes[attr]);
99+
}
100+
}
101+
} else {
102+
// Custom components without XML
103+
componentModule = componentBuilder.getComponentModule(args.elementName, ns, args.attributes, exports);
104+
}
100105
}
101106
} else {
102107
// Default components
103-
componentModule = componentBuilder.getComponentModule(args.elementName, args.namespace, args.attributes, exports);
108+
componentModule = componentBuilder.getComponentModule(args.elementName, ns, args.attributes, exports);
104109
}
105110

106111
if (componentModule) {

ui/builder/template-builder.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ declare module "ui/builder/template-builder" {
66
constructor(templateProperty: TemplateProperty);
77

88
elementName: string;
9-
addStartElement(elementName: string, attributes: Object);
10-
addEndElement(elementName: string);
9+
addStartElement(prefix: string, namespace: string, elementName: string, attributes: Object);
10+
addEndElement(prefix: string, elementName: string);
1111
build();
1212
}
1313

ui/builder/template-builder.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,16 @@ export class TemplateBuilder {
1515
return this._templateProperty.elementName;
1616
}
1717

18-
public addStartElement(elementName: string, attributes: Object) {
19-
this._items.push("<" + elementName + (attributes ? " " + getAttributesAsString(attributes) + ">" : ">"));
18+
public addStartElement(prefix: string, namespace: string, elementName: string, attributes: Object) {
19+
this._items.push("<" +
20+
getElementNameWithPrefix(prefix, elementName) +
21+
(namespace ? " " + getNamespace(prefix, namespace) : "") +
22+
(attributes ? " " + getAttributesAsString(attributes) : "") +
23+
">");
2024
}
2125

22-
public addEndElement(elementName: string) {
23-
this._items.push("</" + elementName + ">");
26+
public addEndElement(prefix: string, elementName: string) {
27+
this._items.push("</" + getElementNameWithPrefix(prefix, elementName) + ">");
2428
}
2529

2630
public build() {
@@ -42,4 +46,12 @@ function getAttributesAsString(attributes: Object): string {
4246
}
4347

4448
return result.join(" ");
49+
}
50+
51+
function getElementNameWithPrefix(prefix: string, elementName: string): string {
52+
return (prefix ? prefix + ":" : "") + elementName;
53+
}
54+
55+
function getNamespace(prefix: string, namespace: string): string {
56+
return 'xmlns:' + prefix + '="' + namespace + '"';
4557
}

0 commit comments

Comments
 (0)