From 6b0028afd7b554914b039cdf371e8e30f6e02dac Mon Sep 17 00:00:00 2001 From: DimitrisRK <55595100+DimitrisRK@users.noreply.github.com> Date: Tue, 30 Jun 2020 08:28:04 +0300 Subject: [PATCH] fix(bindable): parent referenced expression-values now load properly using an update call (#8670) closes #8666 closes #6981 closes #5054 --- e2e/ui-tests-app/app/list-view/main-page.ts | 1 + .../app/list-view/parents-expression-page.ts | 27 +++++++++++++ .../app/list-view/parents-expression-page.xml | 20 ++++++++++ .../ui/core/bindable/bindable.ts | 39 ++++++++++++++----- 4 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 e2e/ui-tests-app/app/list-view/parents-expression-page.ts create mode 100644 e2e/ui-tests-app/app/list-view/parents-expression-page.xml diff --git a/e2e/ui-tests-app/app/list-view/main-page.ts b/e2e/ui-tests-app/app/list-view/main-page.ts index 7138d51e3..7689313b6 100644 --- a/e2e/ui-tests-app/app/list-view/main-page.ts +++ b/e2e/ui-tests-app/app/list-view/main-page.ts @@ -22,6 +22,7 @@ export function loadExamples() { examples.set("width-percent", "list-view/width-percent-page"); examples.set("item-re-layout", "list-view/item-re-layout-page"); examples.set("safe-area", "list-view/safe-area-page"); + examples.set("parents-expression", "list-view/parents-expression-page"); return examples; } diff --git a/e2e/ui-tests-app/app/list-view/parents-expression-page.ts b/e2e/ui-tests-app/app/list-view/parents-expression-page.ts new file mode 100644 index 000000000..fe060077b --- /dev/null +++ b/e2e/ui-tests-app/app/list-view/parents-expression-page.ts @@ -0,0 +1,27 @@ +import { fromObject } from "tns-core-modules/data/observable"; + +export function onLoaded(args) +{ + const page = args.object; + page.bindingContext = fromObject( + { + prefix: "This is a prefix for: ", + languageData: [ + { + name: "English", + }, + { + name: "Portuguese" + }, + { + name: "Spanish" + }, + { + name: "Russian" + }, + { + name: "Greek" + } + ] + }); +} diff --git a/e2e/ui-tests-app/app/list-view/parents-expression-page.xml b/e2e/ui-tests-app/app/list-view/parents-expression-page.xml new file mode 100644 index 000000000..79aab83ef --- /dev/null +++ b/e2e/ui-tests-app/app/list-view/parents-expression-page.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + diff --git a/nativescript-core/ui/core/bindable/bindable.ts b/nativescript-core/ui/core/bindable/bindable.ts index 46428f254..0ce92d63b 100644 --- a/nativescript-core/ui/core/bindable/bindable.ts +++ b/nativescript-core/ui/core/bindable/bindable.ts @@ -469,30 +469,51 @@ export class Binding { let parentViewAndIndex: { view: ViewBase, index: number }; let parentView; let addedProps = newProps || []; - if (expression.indexOf(bc.bindingValueKey) > -1) { + let expressionCP = expression; + if (expressionCP.indexOf(bc.bindingValueKey) > -1) { model[bc.bindingValueKey] = model; addedProps.push(bc.bindingValueKey); } - if (expression.indexOf(bc.parentValueKey) > -1) { - parentView = this.getParentView(this.target.get(), bc.parentValueKey).view; - if (parentView) { - model[bc.parentValueKey] = parentView.bindingContext; - addedProps.push(bc.parentValueKey); - } - } + let success: boolean = true; - let parentsArray = expression.match(parentsRegex); + let parentsArray = expressionCP.match(parentsRegex); if (parentsArray) { for (let i = 0; i < parentsArray.length; i++) { + // This prevents later checks to mistake $parents[] for $parent + expressionCP = expressionCP.replace(parentsArray[i], ""); parentViewAndIndex = this.getParentView(this.target.get(), parentsArray[i]); if (parentViewAndIndex.view) { model[bc.parentsValueKey] = model[bc.parentsValueKey] || {}; model[bc.parentsValueKey][parentViewAndIndex.index] = parentViewAndIndex.view.bindingContext; addedProps.push(bc.parentsValueKey); } + else + { + success = false; + } } } + + if (expressionCP.indexOf(bc.parentValueKey) > -1) { + parentView = this.getParentView(this.target.get(), bc.parentValueKey).view; + if (parentView) { + model[bc.parentValueKey] = parentView.bindingContext; + addedProps.push(bc.parentValueKey); + } + else + { + success = false; + } + } + + // For expressions, there are also cases when binding must be updated after component is loaded (e.g. ListView) + if (!success) + { + let targetInstance = this.target.get(); + targetInstance.off("loaded", this.loadedHandlerVisualTreeBinding, this); + targetInstance.on("loaded", this.loadedHandlerVisualTreeBinding, this); + } } private getSourcePropertyValue() {