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() {
|
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,21 +144,16 @@ 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) {
|
var bindOptions = bindingBuilder.getBindingOptions(propertyName, getBindingExpressionFromAttribute(propertyValue));
|
||||||
attachEventBinding(instance, propertyName, propertyValue);
|
instance.bind({
|
||||||
} else {
|
sourceProperty: bindOptions[bindingBuilder.bindingConstants.sourceProperty],
|
||||||
var bindOptions = bindingBuilder.getBindingOptions(propertyName, getBindingExpressionFromAttribute(propertyValue));
|
targetProperty: bindOptions[bindingBuilder.bindingConstants.targetProperty],
|
||||||
instance.bind({
|
expression: bindOptions[bindingBuilder.bindingConstants.expression],
|
||||||
sourceProperty: bindOptions[bindingBuilder.bindingConstants.sourceProperty],
|
twoWay: bindOptions[bindingBuilder.bindingConstants.twoWay]
|
||||||
targetProperty: bindOptions[bindingBuilder.bindingConstants.targetProperty],
|
}, bindOptions[bindingBuilder.bindingConstants.source]);
|
||||||
expression: bindOptions[bindingBuilder.bindingConstants.expression],
|
} else if (view.isEventOrGesture(propertyName, instance)) {
|
||||||
twoWay: bindOptions[bindingBuilder.bindingConstants.twoWay]
|
|
||||||
}, bindOptions[bindingBuilder.bindingConstants.source]);
|
|
||||||
}
|
|
||||||
} 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();
|
||||||
}
|
}
|
||||||
|
@ -188,12 +188,12 @@ export class Binding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static getProperties(property: string): Array<string> {
|
private static getProperties(property: string): Array<string> {
|
||||||
if (property) {
|
if (property) {
|
||||||
return property.split(".");
|
return property.split(".");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private resolveObjectsAndProperties(source: Object, propsArray: Array<string>) {
|
private resolveObjectsAndProperties(source: Object, propsArray: Array<string>) {
|
||||||
@ -336,8 +336,8 @@ export class Binding {
|
|||||||
|
|
||||||
this.prepareContextForExpression(context, expression);
|
this.prepareContextForExpression(context, expression);
|
||||||
|
|
||||||
model[contextKey] = context;
|
model[contextKey] = context;
|
||||||
return exp.getValue(model, isBackConvert, changedModel);
|
return exp.getValue(model, isBackConvert, changedModel);
|
||||||
}
|
}
|
||||||
return new Error(expression + " is not a valid expression.");
|
return new Error(expression + " is not a valid expression.");
|
||||||
}
|
}
|
||||||
@ -484,10 +484,10 @@ export class Binding {
|
|||||||
|
|
||||||
private getParentView(target, property) {
|
private getParentView(target, property) {
|
||||||
if (!target || !(target instanceof viewModule.View)) {
|
if (!target || !(target instanceof viewModule.View)) {
|
||||||
return {view: null, index: null};
|
return { view: null, index: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
var result;
|
var result;
|
||||||
if (property === bc.parentValueKey) {
|
if (property === bc.parentValueKey) {
|
||||||
result = target.parent;
|
result = target.parent;
|
||||||
}
|
}
|
||||||
@ -499,7 +499,7 @@ export class Binding {
|
|||||||
if (indexParams && indexParams.length > 1) {
|
if (indexParams && indexParams.length > 1) {
|
||||||
index = indexParams[2];
|
index = indexParams[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isNaN(index)) {
|
if (!isNaN(index)) {
|
||||||
var indexAsInt = parseInt(index);
|
var indexAsInt = parseInt(index);
|
||||||
while (indexAsInt > 0) {
|
while (indexAsInt > 0) {
|
||||||
@ -544,10 +544,16 @@ export class Binding {
|
|||||||
this.updating = true;
|
this.updating = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (optionsInstance instanceof observable.Observable) {
|
if (optionsInstance instanceof viewModule.View &&
|
||||||
optionsInstance.set(options.property, value);
|
viewModule.isEventOrGesture(options.property, optionsInstance) &&
|
||||||
|
types.isFunction(value)) {
|
||||||
|
optionsInstance.on(options.property, value, optionsInstance.bindingContext);
|
||||||
} else {
|
} else {
|
||||||
optionsInstance[options.property] = value;
|
if (optionsInstance instanceof observable.Observable) {
|
||||||
|
optionsInstance.set(options.property, value);
|
||||||
|
} else {
|
||||||
|
optionsInstance[options.property] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
|
@ -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