Tutorial Index - how I do self study on the following topics
Part1 - UI5 Module lazy load mechanism
Part2 - Control renderer
Part3 - Html native event VS UI5 semantic event
Part4 - Control metadata
Part5 - Control instance data - how are function setXXX() and getXXX() implemented
Part6 - this blog
Content of this blog
In the previous blog, when we discuss the implementation detail of function setText of Button control, we find that every time a new value is set for text property, there is also a Model Property update operation done ( line 29711 below ).
In this blog, I will study the implementation detail of property binding for Button control. I add another five new lines of code highlighted below in the sample application. It is expected that when the button is displayed, the text for it is not the "Button" passed to Button constructor, but the value "Jerry" from model field "field_for_text".
The aim of this blog is to figure out what has happened under the hood, when the new five lines are executed.
var oModel = new sap.ui.model.json.JSONModel();
When this line is executed, the corresponding JavaScript file for JSONModel will be downloaded. We have already learned this "UI5 module lazy load mechanism" in the first blog.
Let's review our learning regarding prototype chain so far: BaseObject -> EventProvider -> ManagedObject -> Element -> Control.
Here for JSONModel, we can learn another chain.
This prototype chain can be found from the callstacks below. The root node in the prototype chain is again BaseObject. The whole chain is:
BaseObject -> EventProvider -> MessageProcessor -> Model -> ClientModel -> JSONModel
From the source code of JSONModel we can also know that our codes in the sample application regarding JSON model initialization could even be reduced.
Original code:
var oModel = new sap.ui.model.json.JSONModel(); var myData = {"field_for_text": "Jerry"}; oModel.setData(myData);
Reduced code:
var oModel = new sap.ui.model.json.JSONModel( {"field_for_text": "Jerry"} );
However in order to figure out what has happened during each line execution, I keep to use the original lengthy code.
In Model's constructor, we can find the three default Supported binding modes:
Since I have not passed any data into the JSONModel constructor, so new sap.ui.model.json.JSONModel() will only return an empty JSON Model instance.
var myData = {"field_for_text": "Jerry"};
Nothing special, just create a new object for later usage.
oModel.setData(myData);
We don't specify any value for parameter bMerge, so simply assign the oData passed in to this.oData ( line 66 ).
In checkUpdate, since so far the JSON model instance has no binding assigned, so it will do nothing and just return.
oButton1.setModel(oModel);
This line binds the JSON model instance to button instance.
- line 32186 ~ 32192: if current control always has one model named "sName" bound, destroy the old binding relationship first. In my example, this is not the case so we will not enter this IF branch.
- line 32195: from this line we can come to a conclusion that one control could be bound to multiple model with different name, the binding relationship is maintained in the central array this.oModels with model name as key.
- line 32198: if the control has children control in its aggregation, the binding relationship against current model is propagated to all of its children control. In my simple application, the Button control does not have any children controls, so this function simply returns.
line 32200: so far, there is not any BindingContext to be updated, since till now we only bind the Button control as a whole to the JSON model, but never bind any Button property to JSON model field yet. The variable this.mBindingInfos in line 32067 is empty, so again the function updateBindingContext, as well as updateBindings ( line 32202 ) just return.
oButton1.bindProperty("text", "/field_for_text");
- In bindProperty function, since we only pass the binding path, so only sPath is filled, the binding formatter and binding model are undefined.
- A BindingInfo object is constructed in line 31198.
The binding information is stored in the central array this.mBindingInfos and after that _bindProperty function is called.
this._bindProperty(sName, oBindingInfo);
The main logic of control binding with JSON Model field is done in this function.
1. In line 31319, a binding instance is created by oModel.bindProperty.
2. In line 31331, the created binding instance is inserted to array aBindings.
oModel.bindProperty
The implementation of this function:
JSONModel.prototype.bindProperty = function(sPath, oContext, mParameters) { var oBinding = new JSONPropertyBinding(this, sPath, oContext, mParameters); return oBinding; };
Here we have learned the third prototype chain:
BaseObject -> EventProvider -> Binding -> PropertyBinding -> ClientPropertyBinding -> JSONPropertyBinding
The value for Button property "text" to be displayed in the UI, is maintained in this very JSONPropertyBinding instance and filled in the constructor of ClientPropertyBinding.
this._getValue()
This function extracts the data from the field oData of model instance by property name.
So far, the control property binding is done. What is the status of Button control after bindProperty function is executed? Starting from control instance, we can find the value of text property to be displayed from the path oButton1.mBindingInfos.text.binding.oValue, which is filled by function _getValue we have learned in the previous step.
This is the reason why we see "Jerry" in the final rendered UI.