“onBeforeRendering” or “onAfterRendering” is not called every time the view is opened

前端 未结 4 787
庸人自扰
庸人自扰 2020-12-11 07:16

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

4条回答
  •  南方客
    南方客 (楼主)
    2020-12-11 08:00

    1. 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.


    1. 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 on its child, view). Documentation about those events can be found in:

    • API reference: sap.m.NavContainerChild
    • Topic Events Fired on the Pages

    See also a similar question Why does onBeforeFirstShow work?


    1. 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),
    • and the above mentioned routing events like patternMatched (3rd approach).

    The answer is, as always, it depends on what you're trying to achieve. But usually, we:

    • Use the 2nd approach (NavContainerChild events) if the application does not have a routing concept (no sap.ui5/routing in manifest.json).
    • Use the 2nd approach with 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:

      1. When router.navTo() is called, the next corresponding view and controller are created.
      2. In onInit of the newly created controller, you assign a patternMatched handler.
      3. On navigation, the URL hash value will change. The router (internally the HashChanger) notices the URL change, leading to Route firing patternMatched by which your handler will be invoked. See the TL;DR below.
    • ⚠️ 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.


    TL;DR

    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.

提交回复
热议问题