In my UI5 app, I have a view with a table (sap.m.Table
), populated by data coming from the back-end at onInit
hook. The problem is that onInit is e
The answers of Boghyon Hoffmann and Bernard are currently the best solution to the problem of needing an event to perform some action when the page is navigated to.
There is an option where it's possible to configure the target of a route to clear the control aggregation and force it to be re-rendered every time it is navigated to. With this configurantion the events onBeforeRendering
and onAfterRendering
will be called when navigating to the page. However, it is not a recommended solution as it will cause performance issues with the constant re-rendering and it should set to false when working with sap.m.NavContainer or it would cause transitions stop happening and other issues. If you are working on a legacy project that uses sap.ui.ux3.Shell
, which is currently deprecated, it is a possible solution.
So to configure this option we need to set the option clearControlAggregation
to true in the manifest.json, it is false by default when using sap.m.routing.Router
.
In this link you can check all the options you have for the route targets: https://sapui5.hana.ondemand.com/#/api/sap.ui.core.routing.Targets
"config": {
"routerClass": "sap.ui.core.routing.Router",
"viewPath": "TestApp.view",
"viewType": "XML",
"clearControlAggregation": true,
"controlId": "Main",
"controlAggregation": "pages",
"transition": "slide"
}
It is also possible to add this option only for a specific target like this:
"targets": {
"Test1": {
"viewType": "XML",
"viewName": "Test1",
"clearControlAggregation": true,
"title": "Test1"
},
"Test2": {
"viewType": "XML",
"viewName": "Test2",
"title": "Test2"
}
}
- Why (...) is the
onBeforeRendering
not triggered every time the view is displayed?
I think there is a misconception of what "rendering" means. In UI5, when something is "rendering", a complete new DOM element is being (re-)written by the RenderManager
; i.e. onBeforeRendering
is called before the render
-function of the control (View) is called.src
It does not mean that it's called before the browser paints the element to the screen (For that, modern browsers provide native APIs such as Intersection Observer).
Coming back to the question; the reason why on*Rendering
is not triggered, is because the control has been already rendered before. This can be seen when user navigates via navTo
and then back again. The corresponding view element is already in the DOM, so there is no need to call render
again, meaning no on*Rendering
triggered.
What does the code snippet exactly do?
onInit: function () { this.getView().addEventDelegate({ onBeforeShow: this.onBeforeShow, }, this); }
addEventDelegate
adds a listener to the events that are fired on the control (not by the control).
E.g.: The view contains events like afterInit
, beforeExit
, ...
Doing addEventDelegate({onAfterInit})
won't work since afterInit
is fired by this control (view).
Doing addEventDelegate({onmouseover})
works since it's fired on this control.
The same applies to the onBeforeShow
. The view doesn't contain any events like beforeShow
, afterShow
, etc.. Those are fired on the view by the NavContainer
(e.g. by <App>
on its child, view). Documentation about those events can be found in:
See also a similar question Why does onBeforeFirstShow work?
- The alternative technique: to use
patternMatched
(...). But which one of these three approaches is more common?
By "three approaches" I assume you mean:
on*Rendering
(1st approach),on*Show
(2nd approach),patternMatched
(3rd approach).The answer is, as always, it depends on what you're trying to achieve. But usually, we:
NavContainerChild
events) if the application does not have a routing concept (no sap.ui5/routing
in manifest.json).onAfterShow
if the intent is to set initial focus after the view is displayed. See How to Set Initial Focus in a View?Use the 3rd approach to get notified about the route pattern being matched. This approach is commonly used to do something every time the view (NavContainerChild
) is displayed, for example, to do Context Binding after navigating to a detail page. How it works:
router.navTo()
is called, the next corresponding view and controller are created.onInit
of the newly created controller, you assign a patternMatched
handler.⚠️ Personal opinion: avoid 1st approach as an application developer. Avoid doing anything in onBeforeRendering
and in onAfterRendering
since it's unpredictable how often the render
function is called from the viewpoint of the application. For control developers, those hooks are absolutely necessary. But for application developers, there are often better alternatives.
onInit: function() {
const myRoute = this.getOwnerComponent().getRouter().getRoute("routeName");
myRoute.attachPatternMatched(this.onMyRoutePatternMatched, this);
},
onMyRoutePatternMatched: function(event) {
// your code when the view is about to be displayed ..
},
Forget on(Before|After)Rendering
.
Question #3:
patternMatched
is going to get hit when your router is matched on the URL or on the router.navTo
method.
routeMatched
is going to get hit on the same occasion as patternMatched
and when its child routes get navigated to.
Imagine, you have a master view on route A and it’s detail on route B. If the user navigates directly to route B, it makes sense to render the target associated to route B and also the target associated to route A.
To conclude:
patternMatched
: direct route match
routeMatched
:
nestedRoute
parameter is set with the instance of nested route.You should use
onInit: function() {
let route = this.getOwnerComponent().getRouter().getRoute("yourroutename");
route.attachPatternMatched(this.onRoutePatternMatched, this);
// ...
},
This route event will be triggered every time the route pattern is matched in your routing config. In the above example, the function onRoutePatternMatched
will be called every time the route is loaded through navigation.
onRoutePatternMatched: function(event) {
// this logic will repeat itself every time the route pattern is matched
},