mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-17 04:41:36 +08:00
Support for binding expressions in event bindings
This commit is contained in:
@ -560,6 +560,43 @@ export function test_parse_ShouldParseNestedListViewInListViewTemplate() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function test_parse_ShouldEvaluateEventBindingExpressionInListViewTemplate() {
|
||||||
|
var p = <Page>builder.parse('<Page xmlns="http://www.nativescript.org/tns.xsd"><ListView items="{{ items }}" itemLoading="{{ itemLoading }}"><ListView.itemTemplate><SegmentedBar items="{{ $parents[\'ListView\'].items }}" selectedIndexChanged="{{ $parents[\'ListView\'].changed }}" /></ListView.itemTemplate></ListView></Page>');
|
||||||
|
|
||||||
|
function testAction(views: Array<viewModule.View>) {
|
||||||
|
var ctrl: segmentedBar.SegmentedBar;
|
||||||
|
var changed;
|
||||||
|
|
||||||
|
var obj = new observable.Observable();
|
||||||
|
obj.set("items", [1, 2, 3]);
|
||||||
|
|
||||||
|
obj.set("itemLoading", function (args: listViewModule.ItemEventData) {
|
||||||
|
ctrl = <segmentedBar.SegmentedBar>args.view
|
||||||
|
});
|
||||||
|
|
||||||
|
obj.set("changed", function (args: observable.EventData) {
|
||||||
|
changed = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
p.bindingContext = obj;
|
||||||
|
|
||||||
|
TKUnit.wait(0.2);
|
||||||
|
|
||||||
|
ctrl.selectedIndex = 1;
|
||||||
|
|
||||||
|
TKUnit.assert(changed, "Expected result: true!; Actual result: " + changed);
|
||||||
|
};
|
||||||
|
|
||||||
|
helper.navigate(function () { return p; });
|
||||||
|
|
||||||
|
try {
|
||||||
|
testAction([p.content, p]);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
helper.goBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function test_parse_NestedRepeaters() {
|
export function test_parse_NestedRepeaters() {
|
||||||
var pageXML =
|
var pageXML =
|
||||||
"<Page xmlns='http://www.nativescript.org/tns.xsd'>" +
|
"<Page xmlns='http://www.nativescript.org/tns.xsd'>" +
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import observable = require("data/observable");
|
import view = require("ui/core/view");
|
||||||
import view = require("ui/core/view");
|
|
||||||
import bindable = require("ui/core/bindable");
|
import bindable = require("ui/core/bindable");
|
||||||
import types = require("utils/types");
|
import types = require("utils/types");
|
||||||
import definition = require("ui/builder/component-builder");
|
import definition = require("ui/builder/component-builder");
|
||||||
import fs = require("file-system");
|
import fs = require("file-system");
|
||||||
import gestures = require("ui/gestures");
|
|
||||||
import bindingBuilder = require("ui/builder/binding-builder");
|
import bindingBuilder = require("ui/builder/binding-builder");
|
||||||
import platform = require("platform");
|
import platform = require("platform");
|
||||||
import pages = require("ui/page");
|
import pages = require("ui/page");
|
||||||
@ -29,8 +27,6 @@ var MODULES = {
|
|||||||
var CODEFILE = "codeFile";
|
var CODEFILE = "codeFile";
|
||||||
var CSSFILE = "cssFile";
|
var CSSFILE = "cssFile";
|
||||||
|
|
||||||
var eventHandlers = {};
|
|
||||||
|
|
||||||
export function getComponentModule(elementName: string, namespace: string, attributes: Object, exports: Object): definition.ComponentModule {
|
export function getComponentModule(elementName: string, namespace: string, attributes: Object, exports: Object): definition.ComponentModule {
|
||||||
var instance: view.View;
|
var instance: view.View;
|
||||||
var instanceModule: Object;
|
var instanceModule: Object;
|
||||||
@ -140,8 +136,6 @@ export function getComponentModule(elementName: string, namespace: string, attri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eventHandlers = {};
|
|
||||||
|
|
||||||
componentModule = { component: instance, exports: instanceModule, bindings: bindings };
|
componentModule = { component: instance, exports: instanceModule, bindings: bindings };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,12 +144,8 @@ export function getComponentModule(elementName: string, namespace: string, attri
|
|||||||
|
|
||||||
export function setPropertyValue(instance: view.View, instanceModule: Object, exports: Object, propertyName: string, propertyValue: string) {
|
export function setPropertyValue(instance: view.View, instanceModule: Object, exports: Object, propertyName: string, propertyValue: string) {
|
||||||
// Note: instanceModule can be null if we are loading custom compnenet with no code-behind.
|
// Note: instanceModule can be null if we are loading custom compnenet with no code-behind.
|
||||||
var isEventOrGesture: boolean = isKnownEventOrGesture(propertyName, instance);
|
|
||||||
|
|
||||||
if (isBinding(propertyValue) && instance.bind) {
|
if (isBinding(propertyValue) && instance.bind) {
|
||||||
if (isEventOrGesture) {
|
|
||||||
attachEventBinding(instance, propertyName, propertyValue);
|
|
||||||
} else {
|
|
||||||
var bindOptions = bindingBuilder.getBindingOptions(propertyName, getBindingExpressionFromAttribute(propertyValue));
|
var bindOptions = bindingBuilder.getBindingOptions(propertyName, getBindingExpressionFromAttribute(propertyValue));
|
||||||
instance.bind({
|
instance.bind({
|
||||||
sourceProperty: bindOptions[bindingBuilder.bindingConstants.sourceProperty],
|
sourceProperty: bindOptions[bindingBuilder.bindingConstants.sourceProperty],
|
||||||
@ -163,8 +153,7 @@ export function setPropertyValue(instance: view.View, instanceModule: Object, ex
|
|||||||
expression: bindOptions[bindingBuilder.bindingConstants.expression],
|
expression: bindOptions[bindingBuilder.bindingConstants.expression],
|
||||||
twoWay: bindOptions[bindingBuilder.bindingConstants.twoWay]
|
twoWay: bindOptions[bindingBuilder.bindingConstants.twoWay]
|
||||||
}, bindOptions[bindingBuilder.bindingConstants.source]);
|
}, bindOptions[bindingBuilder.bindingConstants.source]);
|
||||||
}
|
} else if (view.isEventOrGesture(propertyName, instance)) {
|
||||||
} else if (isEventOrGesture) {
|
|
||||||
// Get the event handler from page module exports.
|
// Get the event handler from page module exports.
|
||||||
var handler = exports && exports[propertyValue];
|
var handler = exports && exports[propertyValue];
|
||||||
|
|
||||||
@ -196,33 +185,6 @@ export function setPropertyValue(instance: view.View, instanceModule: Object, ex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function attachEventBinding(instance: view.View, eventName: string, value: string) {
|
|
||||||
// Get the event handler from instance.bindingContext.
|
|
||||||
eventHandlers[eventName] = (args: observable.PropertyChangeData) => {
|
|
||||||
if (args.propertyName === "bindingContext") {
|
|
||||||
var handler = instance.bindingContext && instance.bindingContext[getBindingExpressionFromAttribute(value)];
|
|
||||||
// Check if the handler is function and add it to the instance for specified event name.
|
|
||||||
if (types.isFunction(handler)) {
|
|
||||||
instance.on(eventName, handler, instance.bindingContext);
|
|
||||||
}
|
|
||||||
instance.off(observable.Observable.propertyChangeEvent, eventHandlers[eventName]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
instance.on(observable.Observable.propertyChangeEvent, eventHandlers[eventName]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isKnownEventOrGesture(name: string, instance: any): boolean {
|
|
||||||
if (types.isString(name)) {
|
|
||||||
var evt = `${name}Event`;
|
|
||||||
|
|
||||||
return instance.constructor && evt in instance.constructor ||
|
|
||||||
gestures.fromString(name.toLowerCase()) !== undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBindingExpressionFromAttribute(value: string): string {
|
function getBindingExpressionFromAttribute(value: string): string {
|
||||||
return value.replace("{{", "").replace("}}", "").trim();
|
return value.replace("{{", "").replace("}}", "").trim();
|
||||||
}
|
}
|
||||||
|
@ -544,12 +544,18 @@ export class Binding {
|
|||||||
this.updating = true;
|
this.updating = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (optionsInstance instanceof viewModule.View &&
|
||||||
|
viewModule.isEventOrGesture(options.property, optionsInstance) &&
|
||||||
|
types.isFunction(value)) {
|
||||||
|
optionsInstance.on(options.property, value, optionsInstance.bindingContext);
|
||||||
|
} else {
|
||||||
if (optionsInstance instanceof observable.Observable) {
|
if (optionsInstance instanceof observable.Observable) {
|
||||||
optionsInstance.set(options.property, value);
|
optionsInstance.set(options.property, value);
|
||||||
} else {
|
} else {
|
||||||
optionsInstance[options.property] = value;
|
optionsInstance[options.property] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
trace.write("Binding error while setting property " + options.property + " of " + optionsInstance + ": " + ex,
|
trace.write("Binding error while setting property " + options.property + " of " + optionsInstance + ": " + ex,
|
||||||
trace.categories.Binding,
|
trace.categories.Binding,
|
||||||
|
@ -15,6 +15,17 @@ import color = require("color");
|
|||||||
import animationModule = require("ui/animation");
|
import animationModule = require("ui/animation");
|
||||||
import observable = require("data/observable");
|
import observable = require("data/observable");
|
||||||
|
|
||||||
|
export function isEventOrGesture(name: string, view: View): boolean {
|
||||||
|
if (types.isString(name)) {
|
||||||
|
var evt = `${name}Event`;
|
||||||
|
|
||||||
|
return view.constructor && evt in view.constructor ||
|
||||||
|
gestures.fromString(name.toLowerCase()) !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
export function getViewById(view: View, id: string): View {
|
export function getViewById(view: View, id: string): View {
|
||||||
if (!view) {
|
if (!view) {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
2
ui/core/view.d.ts
vendored
2
ui/core/view.d.ts
vendored
@ -30,6 +30,8 @@ declare module "ui/core/view" {
|
|||||||
*/
|
*/
|
||||||
export function getAncestor(view: View, criterion: string | Function): View;
|
export function getAncestor(view: View, criterion: string | Function): View;
|
||||||
|
|
||||||
|
export function isEventOrGesture(name: string, view: View): boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines interface for an optional parameter used to create a view.
|
* Defines interface for an optional parameter used to create a view.
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user