UI5 extension of controller and lifecycle methods

Viewed 1923

I'm trying to create a base controller that has common methods and common onInit logic.

Using the extend method adds the methods from the base controller to the child controller, but the lifecycle methods get overwritten completely.

  • I tried using the override.onInit approach shown on this documentation page but it did not work.
  • I also tried with sap.ui.component like this but I couldn't get it to work at all.
    I'm not sure if it should work with the AMD syntax.

As far as I understood, the extension feature should replace common methods that have been overridden, but it should execute the lifecycle methods from both the base and extension controller on this respective order.

So my question are the following:

  1. Is this behavior possible to achieve? If so, what am I doing wrong?
  2. Is there a better way to implement it?

Example code:

Parent controller

sap.ui.define([
  "sap/ui/core/mvc/Controller"
], function (Controller) {
  "use strict";

  return Controller.extend("my.namespace.controller.App", {
    onInit: function () {
      console.log("reusable init");
    },

    // ...
  });
});

Child controller

sap.ui.define([
  "my/namespace/controller/App.controller"
], function (Controller) {
  "use strict";

  return Controller.extend("my.namespace.child.controller.App", {
    onInit: function () {
      console.log("extend init");
    },

    // ...
  });
});

This example logs only "extend init" when I run the application. I expected it to log both "reusable init" and "extend init" in this order.

I've omitted some code, but the main idea is represented on these two controllers. The only relevant metadata is that the base controller is abstract.

2 Answers

In many cases, when developing applications from scratch, the BaseController approach is sufficient as Benedikt explained, or you could try composition with many tiny modules, depending on your project.

The topic controller extension is lesser-known, yet worth to get to know what it's about and how extensions can also help us in application development.

The documentation does hint that the extension concepts usually target developers who want to extend existing applications with additional features. But extensions can be also used to reuse some logic in your own application development.

[Controller extensions] can be used [...] as a reusable part that is added to the original application. (Source)

There are currently two approaches:

  1. The older concept named "Component Configuration"
    (The extensions are declared in manifest.json or formerly in Component.js)

    • Supported by older UI5 versions.
    • Lifecycle methods are called in addition to the original ones (See table below).
    • Non-lifecycle methods, with the same name, are fully overwritten by the extension.
    • Simple and declarative, but it's missing the possibility to define a clear interface which methods can be extended in which order.

    See, this plunk for example.

  2. The newer concept called "Controller Extension"
    (Uses the module "sap/ui/core/mvc/ControllerExtension" and the methods section within controller's metadata)

    • Publicly documented since 1.56 but no samples so far.
    • Lifecycle methods are called in addition to the original ones (Same as the old approach).
    • Offers the possibility to define a clear interface:
      • Visibility (public: true | false)
      • Overridability (final: true | false)
      • Execution strategy (overrideExecution: "After" | "Before" | "Instead")
      • Allows extending extension methods in the base controller itself via the static ControllerExtension.override method.
    • Can be used to add reusable JS parts (Equivalent to the fragment concept).

    See this plunk for example.

Lifecycle execution order

In either case, UI5 executes the lifecycle methods in the following order by default:

Execution order Original controller code Extension code
1. onInit
2. onInit
3. onBeforeRendering
4. onBeforeRendering
5. onAfterRendering
6. onAfterRendering
7. onExit
8. onExit

I didn't know there is an override mechanise in UI5 and it looks over-engineered... My guess is you are on an older version without proper support.

Anyhow, js-inheritance works out of the box. You need to call "super".

sap.ui.define([
        "example/BaseController"
    ], function (BaseController) {
        "use strict";
    
        return BaseController.extend("example.BaseController2", {
            onInit: function () {
                // this is the "super" call
                // same happens if you call super() on es6 classes
                BaseController.prototype.onInit.apply(this, arguments);
         }
    });
});

For more information have a look here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain

Related