loio |
---|
21515f09c0324218bb705b27407f5d61 |
view on: demo kit nightly build | demo kit latest release
Controller extensions allow you to add functionality to existing applications. They can be used for extensibility purposes, for example by a customer wishing to extend SAP-delivered applications, or as a reusable part that is added to the original application.
The following sample code shows how to define an extension for an existing controller.
sap.ui.define(['sap/ui/core/mvc/ControllerExtension', 'sap/ui/core/mvc/OverrideExecution'], function(ControllerExtension, OverrideExecution) {
"use strict";
return ControllerExtension.extend("my.extension.SampleExtension", {
metadata: {
// extension can declare the public methods
// in general methods that start with "_" are private
methods: {
publicMethod: {
public: true /*default*/ ,
final: false /*default*/ ,
overrideExecution: OverrideExecution.Instead /*default*/
},
finalMethod: {
final: true
},
onMyHook: {
public: true /*default*/ ,
final: false /*default*/ ,
overrideExecution: OverrideExecution.After
},
couldBePrivate: {
public: false
}
}
},
// adding a private method, only accessible from this controller extension
_privateMethod: function() {},
// adding a public method, might be called from or overridden by other controller extensions as well
publicMethod: function() {},
// adding final public method, might be called from, but not overridden by other controller extensions as well
finalMethod: function() {},
// adding a hook method, might be called from but not overridden by other controller extensions
// overriding these method does not replace the implementation, but executes after the original method
onMyHook: function() {},
// method public by default, but made private via metadata
couldBePrivate: function() {},
// this section allows to extend lifecycle hooks or override public methods of the base controller
override: {
// override onInit of base controller
onInit: function() {},
// override public method of the base controller
basePublicMethod: function() {}
}
});
});
For more detailed information on lifecycle hooks and controller metadata, see Controller.
If you want to have additional lifecycle events like the standard onInit
or onExit
for developers extending the controller, you can define them as described in this section.
Controller extensions allow you to define custom lifecycle hooks. In the sample below, a custom lifecycle hook is defined by specifying an overrideExecution
function:
return ControllerExtension.extend("sap.my.ReuseExtension", {
metadata: {
methods: {
"onFilterHook": {"public": true, "final": false, overrideExecution: OverrideExecution.After}
}
},
//...
/**
* @abstract
*/
onFilterHook: function(aFilter) {
}
});
With OverrideExecution.After
, the extensions are called in the order they are provided, with OverrideExecution.Before
the order is reversed and the last extension is called first.
Adding "final": true
metadata to the public method makes it available for execution (call) but not for overriding in the next controller extension.
return ControllerExtension.extend("sap.my.ReuseExtension", {
metadata: {
methods: {
"myPublicMethod": {"public": true, "final": true}
}
},
myPublicMethod: function() {
}
});
Only controls that belong to an extension are accessible by the byId
function in a controller extension. These controls must be prefixed by the namespace of the controller extension. The namespace can be retrieved by calling getMetadata().getNamespace()
. Here is an example of a valid ID: my.controller.extension.MyControlId
.
Using the byId
of the base controller allows the accessing of all controls of the corresponding view by calling this.base.byId(myControlId)
.
Controller extensions can serve for reuse purposes. You can achieve this by including a controller extension to your controller as a member.
sap.ui.define(['sap/ui/core/mvc/Controller', 'my/extension/SampleExtension'], function(Controller, SampleExtension) {
"use strict";
return Controller.extend("sample.Main", {
//include the extension
sample: SampleExtension,
_basePrivateMethod: function() {
...
},
basePublicMethod: function() {
...
});
});
If the controller is instantiated, all members that have a ControllerExtension
associated will create an instance of these controller extensions.
You can also override an extension directly in a controller.
sap.ui.define(['sap/ui/core/mvc/Controller', 'my/extension/SampleExtension'], function(Controller, SampleExtension) { "use strict"; return MainController = Controller.extend("sample.Main", { //inline override of an extension. E.g. to provide a hook implementation sample: SampleExtension.override({ someHook: function() {}, someOtherMethod: function() {} }), onLifecycleHook: function() { } }); });
For information on integrating controller extensions into controllers in TypeScript, see Assigning Controller Extensions and Overriding Controller Extension Behavior in Using Controller Extension with TypeScript.
In UI5 JavaScript code, controller extensions may have an override
definition block, containing methods like onInit
which are to be overridden by the extension. In TypeScript, the presence of a definition block with the same name as a static member of an ES6 class would lead to a name clash with the static UI5 method sap.ui.core.mvc.ControllerExtension.override
. Furthermore, specifying this block as a static member would not work — regardless of its name — because thetransformer would assign this block as a static member to the transformed UI5 class instead of moving it into the definition block of BaseClass.extend("ClassName", { ... })
where it is expected.
We therefore offer the overrides
keyword as an additional name for this definition block, so that controller extensions can be specified as ES6 classes in TypeScript as shown below. The transformer has been changed to handle the overrides
definition block in the correct way.
/** * @namespace my.sample */ export default class AppExtension extends ControllerExtension { static readonly overrides = { onInit: function() { // ... } } }
The
@namespace
comment is required for the extension class to be known by its full name at runtime, so it can e.g. be referenced in themanifest.json
when applying the controller extension.
The
overrides
keyword is only recognized by UI5 runtime versions 1.112 and higher.When using the UI5 Babel transformer plugin, the
overridesToOverride
option must be set to enable its use with older versions. It then changes theoverrides
keyword back tooverride
, which is recognized by older UI5 runtime versions.When using the ui5-tooling-transpile task and middleware, which is recommended for the most convenient TypeScript setup and internally uses the aforementioned UI5 Babel transformer plugin, you can enable this option by adding the required configuration for ui5-tooling-transpile directly to the
ui5.yaml
file as follows:builder: customTasks: - name: ui5-tooling-transpile-task afterTask: replaceVersion configuration: transformModulesToUI5: overridesToOverride: true [...] server: customMiddleware: - name: ui5-tooling-transpile-middleware afterMiddleware: compression configuration: transformModulesToUI5: overridesToOverride: true
In JavaScript, when a controller uses a pre-defined controller extension, the respective extension class needs to be assigned to the extend
object under an arbitrary property name. In TypeScript, however, the class property should contain an extension instance, as the controller code should interact with an instance — not the class — of the extension.
To support this, the dummy method ControllerExtension.use(...)
is introduced in the UI5 type definitions. This method takes an extension class as its argument and claims to return an instance, allowing you to work with this instance in your controller.
Behind the scenes, the ControllerExtension.use(...)
method call is removed by the UI5 Babel transformer plugin when your TypeScript code is converted to JavaScript, so the UI5 runtime gets the extension class it needs to create a new instance of the extension for each controller instance.
import Routing from "sap/fe/core/controllerextensions/Routing"; import ControllerExtension from "sap/ui/core/mvc/ControllerExtension"; /** * @namespace my.sample */ class MyController extends Controller { routing = ControllerExtension.use(Routing); // use the "Routing" extension provided by sap.fe someMethod() { this.routing.navigate(...); } }
ControllerExtension.use(...)
requiresbabel-plugin-transform-modules-ui5
version 7.5.0 or higher. If you useui5-tooling-transpile
instead, you have to make sure to executenpm update
in your project.To have the transformer plugin recognize and remove the dummy method call, you must do the following:
Call it on the
ControllerExtension
base class (imported fromsap/ui/core/mvc/ControllerExtension
), not on a class deriving from it.Assign the extension right in the class definition using an equal sign (not a colon as in JavaScript).
Some controller extensions allow implementing hooks or overriding their behavior. This can be done equally well in TypeScript:
import Routing from "sap/fe/core/controllerextensions/Routing"; import ControllerExtension from "sap/ui/core/mvc/ControllerExtension"; /** * @namespace my.sample */ class MyController extends Controller { routing = ControllerExtension.use(Routing.override({ someHook: function(...) { ... } })); // adapt the "Routing" extension provided by sap.fe someMethod() { this.routing.navigate(...); } }
Related Information