mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-16 11:42:04 +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() {
|
||||
var pageXML =
|
||||
"<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 types = require("utils/types");
|
||||
import definition = require("ui/builder/component-builder");
|
||||
import fs = require("file-system");
|
||||
import gestures = require("ui/gestures");
|
||||
import bindingBuilder = require("ui/builder/binding-builder");
|
||||
import platform = require("platform");
|
||||
import pages = require("ui/page");
|
||||
@ -29,8 +27,6 @@ var MODULES = {
|
||||
var CODEFILE = "codeFile";
|
||||
var CSSFILE = "cssFile";
|
||||
|
||||
var eventHandlers = {};
|
||||
|
||||
export function getComponentModule(elementName: string, namespace: string, attributes: Object, exports: Object): definition.ComponentModule {
|
||||
var instance: view.View;
|
||||
var instanceModule: Object;
|
||||
@ -140,8 +136,6 @@ export function getComponentModule(elementName: string, namespace: string, attri
|
||||
}
|
||||
}
|
||||
|
||||
eventHandlers = {};
|
||||
|
||||
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) {
|
||||
// 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 (isEventOrGesture) {
|
||||
attachEventBinding(instance, propertyName, propertyValue);
|
||||
} else {
|
||||
var bindOptions = bindingBuilder.getBindingOptions(propertyName, getBindingExpressionFromAttribute(propertyValue));
|
||||
instance.bind({
|
||||
sourceProperty: bindOptions[bindingBuilder.bindingConstants.sourceProperty],
|
||||
@ -163,8 +153,7 @@ export function setPropertyValue(instance: view.View, instanceModule: Object, ex
|
||||
expression: bindOptions[bindingBuilder.bindingConstants.expression],
|
||||
twoWay: bindOptions[bindingBuilder.bindingConstants.twoWay]
|
||||
}, bindOptions[bindingBuilder.bindingConstants.source]);
|
||||
}
|
||||
} else if (isEventOrGesture) {
|
||||
} else if (view.isEventOrGesture(propertyName, instance)) {
|
||||
// Get the event handler from page module exports.
|
||||
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 {
|
||||
return value.replace("{{", "").replace("}}", "").trim();
|
||||
}
|
||||
|
@ -544,12 +544,18 @@ export class Binding {
|
||||
this.updating = true;
|
||||
|
||||
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) {
|
||||
optionsInstance.set(options.property, value);
|
||||
} else {
|
||||
optionsInstance[options.property] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
trace.write("Binding error while setting property " + options.property + " of " + optionsInstance + ": " + ex,
|
||||
trace.categories.Binding,
|
||||
|
@ -15,6 +15,17 @@ import color = require("color");
|
||||
import animationModule = require("ui/animation");
|
||||
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 {
|
||||
if (!view) {
|
||||
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 isEventOrGesture(name: string, view: View): boolean;
|
||||
|
||||
/**
|
||||
* Defines interface for an optional parameter used to create a view.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user