Some comments said UI5 use Handlebars for data binding, and after search, Handlebars only support for one-time data binding. What I am more curious is how two-way data binding implemented in UI5(Sorry for not making this clear in the first place).
In Handlebars,once you compiled your template, the view/DOM has nothing to do with the data model.
But two-way data binding connects data to a property or attribute of an element in its local DOM. Which means:
When properties in the model get updated, so does the UI. When UI elements get updated, the changes get propagated back to the model.
https://stackoverflow.com/a/13504965/5238583
In the question of How to Implement DOM Data Binding in JavaScript
, many techniques are mentioned. UI5 uses these two(what I've found so far): add change event listener and mutators(setter)
I used this official sample for example: Data Binding - Step 13 - Element Binding
data binding changes when
oProductDetailPanel.bindElement({ path: sPath, model: "products" });
is called.
Set break points in oBinding.setContext() in ManagedObject.prototype.updateBindingContext and ManagedObject.prototype.updateProperty. And you can see it in call stack.
TL;DR: Core steps are 3, 6, 8
The main steps are:
Element.prototype.bindElement
equals to ManagedObject.prototype.bindObject
oBinding.initialize() which means ClientContextBinding.prototype.initialize is called in ManagedObject.prototype._bindObject
Binding.prototype._fireChange is called in the createBindingContext
callback. Which fire change
event: this.fireEvent("change", mArguments)
;
And! The change event handler is defined in ManagedObject.prototype._bindObject
:
var fChangeHandler = function(oEvent) {
that.setElementBindingContext(oBinding.getBoundContext(), sModelName);
};
oBinding.attachChange(fChangeHandler);
oBindingInfo.modelChangeHandler = fChangeHandler;
setElementBindingContext()
calls ManagedObject.prototype.updateBindingContext
eventually
In updateBindingContext
, the call stack is oBinding.setContext(oContext)
-> JSONPropertyBinding.prototype.checkUpdate
(because the sample use JSON Model here) -> this._fireChange({reason: ChangeReason.Change})
For the second change event, the handler is in ManagedObject.prototype._bindProperty (There are many fModelChangeHandler
in bind functions of ManagedObject, For our bindElement
sample, we only need this one)
In the fModelChangeHandler
, ManagedObject.prototype.updateProperty
is called. That where our setter(mutator) is used:
whenever a property binding is changed.This method gets the external format from the property binding and applies it to the setter.
this[oPropertyInfo._sMutator](oValue);
. For our sample oPropertyInfo._sMutator
is setValue
. execute this, the value in Input <Input value="{products>ProductID}"/>
will be changed.
Original record here: https://github.com/TinaC/Blog/blob/master/SAPUI5/Data_Binding.md