How I do self-study on a given Fiori control – part 3
- Tutorial Index – how I do self study on the following topics
- Part1 – UI5 Module lazy load mechanism
- Part2 – Control renderer
- Part3 – this blog
- Part4 – Control metadata
- Part5 – Control instance data – how are function setXXX() and getXXX() implemented
- Part6 – Control data binding under the hood
- Part7 – Implementations for different binding mode: OneWay, TwoWay, OneTime
- Part8 – Control ID
- Part9 – Control internationalization support
- Part10 – Button control in XML view
- Part11 – Button control and its underlying DOM
- Content of this blog
Tutorial Index – how I do self study on the following topics
-
Part1 – UI5 Module lazy load mechanism
-
Part2 – Control renderer
-
Part3 – this blog
-
Part4 – Control metadata
-
Part5 – Control instance data – how are function setXXX() and getXXX() implemented
-
Part6 – Control data binding under the hood
-
Part7 – Implementations for different binding mode: OneWay, TwoWay, OneTime
-
Part8 – Control ID
-
Part9 – Control internationalization support
-
Part10 – Button control in XML view
-
Part11 – Button control and its underlying DOM
Content of this blog
In previous part, it is explained how the native html code of Button control is generated by its renderer, ButtonRenderer.js.
“click” event VS “press” event
As we can find in Chrome network tab, the UI5 Button control is represented by native “button” tag. In this part, I will share how I study the event handling logic of this control.
In W3School, we are taught that the event for mouse click on button tag is “onclick”. Quite clear, isn’t it?
Go back to our simple application, you will surprisingly find that no event listener is registered on this button element.
Instead when you click the checkbox “Ancestors”, this time, a event handler for click event, is found to register on its parent node, the div tag with id “content”.
Also in our sample application, we don’t register the handler function on “click” event. Instead we simply pass one object to the Button constructor, which contains one field “press” pointing to a function.
So when user clicks button in the browser, how can UI5 framework know the function we register to the “press” must be called to react on the native “click” event? What is the relationship between “press” and “click”?
The “press” event is defined as one part of metadata in Button.js.
Search the keyword “press” in this file, and one hit is Button.prototype.onclick. To verify whether it is this function which finishs the “translation” from “click” to “press”, we set a breakpoint on it.
In the runtime, when the button is clicked, Button.onClick is called with one JQuery event object of type “click”. It is this onclick function being responsible to delegate the native click event to UI5 event “press”.
“Press” event registration
How does this.firePress finally succeed to call the function “console.log(‘Alert from ‘ + oButton1.getText());” we defined in our sample application?
Debug into the firePress implementation, it simply queries the event handler for press event from a central array, “this.mEventRegistry”.
In our simple application, we never do any explicit event registration, so when and where our event handling is filled into that central event repository array “this.mEventRegistry”?
Still remember the prototype chain described in part 1 ?
BaseObject -> EventProvider -> ManagedObject -> Element -> Control.
The mystery is in EventProvider’s constructor:
In the first chapter of this blog, we find the event handler of the button tag’s parent, the div tag. Click the hyperlink below:
Set the breakpoint there and click the button again. Through callstack you can understand how the mouse click event has been passed from parent div tag to the children button tag:
Summary
The “press” event in this blog is described by SAPUI5 as “semantic events”. Semantic events do not exist as native HTML browser events. The UI control implementation is responsible for mapping native browser events to semantic events. For more details please refer to SAP help: UI Control API: Event Handling.
Event dispatch
According to Andreas‘ comment, the UI5 event design could be summarized as “Event Dispatch”, which is commonly used in many frontend framework.
” the event handler is not added to the <button> tag, but to an ancestor “div tag with id “content””. For performance reasons, UI5 does not add not many event handlers to all the HTML elements, but only to such common ancestor elements, which we call “UIAreas”. The events are centrally handled and then “dispatched” to the controls, where they originated. So the central UI5event handler does register at this ancestor element for the “click” event (and other frequently used events) and when it happens, this central event handler checks where it comes from and checks all controls in this part of the hierarchy, whether any of them implements the “onclick” function and calls it. So this is how the “onclick” function in the Button control is called. “
See another article How JavaScript Event Delegation Works from David Walsh .
Event abstraction
Why UI5 chooses to introduce semantic event? See Andreas’ answer below:
” Those “semantic” control events like the Button’s “press” are also meant to abstract from different platforms: on mouse devices it’s “click”, but on touch devices it’s “touchstart” plus “touchend” (or the combined “tap”). Or it could even be the “space” key when the Button is focused. But for the application it’s only important to know that the Button has been triggered. Maybe in the future you can even trigger Buttons by looking and blinking at them? Hence the Button has its own event, which internally handles all the different ways to trigger the Button. “
Angular Event Handling
If you would also like to know how event handling is implemented in Angular, please read this blog: Compare Event handling mechanism: SAPUI5 and Angular .
In the next blog, I will study the metadata of the Button control.
Good blog!
I'd just like to add some details how the browser "click" event gets to the "onclick" method in the Button control implementation:
While it is correct that you can add event handlers to HTML tags by adding attributes like "onclick", this is not exactly what is happening here, even though the name of the event handler in the Button is (intentionally) the same. The other way to register event handlers in HTML is using the "addEventListener" DOM function. This is what UI5 does.
But - as you correctly noticed, this event handler is not added to the <button> tag, but to an ancestor "div tag with id "content"". For performance reasons, UI5 does not add not many event handlers to all the HTML elements, but only to such common ancestor elements, which we call "UIAreas". The events are centrally handled and then "dispatched" to the controls, where they originated. So the central UI5 event handler does register at this ancestor element for the "click" event (and other frequently used events) and when it happens, this central event handler checks where it comes from and checks all controls in this part of the hierarchy, whether any of them implements the "onclick" function and calls it. So this is how the "onclick" function in the Button control is called.
Those "semantic" control events like the Button's "press" are also meant to abstract from different platforms: on mouse devices it's "click", but on touch devices it's "touchstart" plus "touchend" (or the combined "tap"). Or it could even be the "space" key when the Button is focused. But for the application it's only important to know that the Button has been triggered. Maybe in the future you can even trigger Buttons by looking and blinking at them? Hence the Button has its own event, which internally handles all the different ways to trigger the Button.
Hi Andreas,
Thanks a lot for your informative comment! I have appended them to this blog 🙂
Best regards,
Jerry