Skip to Content
Technical Articles
Author's profile photo Wouter Lemaire

My first experience with TypeScript in UI5 – BaseController

Around April SAP announced for the first time TypeScript Support for UI5. Since then, I’ve tried to use this in every new UI5 project where possible. Now it is time to share my experience with TypeScript in UI5 in this blog post series.

In the previous blog post I generated a new UI5 project with TypeScript using the easy-ui5 generator as a starting point for this blog post series.

This blog post will be an easy one 😊 . Before TypeScript we used templates from WebIDE or BAS/Fiori Tooling as a starting point. In most of the them and in almost every UI5 project we make use of a “BaseController”. TypeScript or not, I still want and will need a BaseController for common functions across the controllers in any UI5 project. In this part of the blog post series I will share the TypeScript version of the BaseController I used.

You can watch the video or continue reading:

Create BaseController

Start by creating a new file “BaseController.ts” in the “src” => “controller” folder. Careful, we now use “.ts” at the end and no “.” between “Base” and “Controller” (this last one is also important without TS):

TypeScript BaseController

I did not start from scratch, instead used a BaseController.js from an earlier project as a starting point. Just as an example, this is how the JS version looks like: https://github.com/lemaiwo/UI5Con2019/blob/master/webapp/controller/BaseController.js

Before converting the JS version I created a new class named “BaseController” which extends from “sap.ui.core.mvc.Controller”. Above the class definition I also add the namespace in comment. This is needed by the TypeScript compiler to convert this to a UI5 controller:

In the BaseController I defined (just like in the JS version) the following functions:

  • getRouter => a wrapper name to get the router object from the Owner Component
  • getModel => a wrapper function to get the model of the current view with an optional model name
  • setModel => a wrapper function to set the model on the current view with again an optional model name
  • getReousrceBundle => a wrapper function which returns the resource bundle of the main i18n model
  • onNavBack => a generic function to navigate back to the previos page or the master page if there is no previous hash

Full code of my BaseController.ts:

import Controller from "sap/ui/core/mvc/Controller";
import History from "sap/ui/core/routing/History";
import Router from "sap/ui/core/routing/Router";
import UIComponent from "sap/ui/core/UIComponent";
import Model from "sap/ui/model/Model";
import ResourceModel from "sap/ui/model/resource/ResourceModel";
import ResourceBundle from "sap/base/i18n/ResourceBundle";
/**
 * @namespace be.wl.TypeScriptServiceDemoApp.controller
 */
export default class BaseController extends Controller {
	public getRouter(): Router {
		return (this.getOwnerComponent() as UIComponent).getRouter();
	}
	public getModel(name?: string): Model {
		return this.getView().getModel(name);
	}
	public setModel(model: Model, name?: string): void {
		this.getView().setModel(model, name);
	}
	public getResourceBundle(): ResourceBundle {
		return (((this.getOwnerComponent() as UIComponent).getModel("i18n") as ResourceModel).getResourceBundle() as ResourceBundle);
	}
	public onNavBack(): void {
		const sPreviousHash = History.getInstance().getPreviousHash();

		if (sPreviousHash !== undefined) {
			// eslint-disable-next-line
			history.go(-1);
		} else {
			this.getRouter().navTo("master", {},{}, true);
		}
	}
}

 

You can also find it back in this GitHub project: https://github.com/lemaiwo/TypeScriptServiceDemoApp/blob/main/src/controller/BaseController.ts

 

 

Use TypeScript BaseController

After creating the BaseController, I updated the already existing controllers to extend from the BaseController instead of “sap.ui.core.mvc.Controller”:

From now on I will use the BaseController in every new controller.

 

This is a small but fundamental part of any UI5 app when you start developing a new app.

Assigned Tags

      2 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Marc Schleeweiß
      Marc Schleeweiß

      Hey Wouter, thanks for the article, good start for devs who want to make the switch to TS 🙂

      I have one question:

      The return type of the method sap/ui/model/resource/ResourceModel.getResourceBundle() is ResourceBundle | Promise<ResourceBundle> according to the docs (and also according to the auto completion 😉)

      Is it safe to ignore the second case (promise) as you did in your BaseController?

       

      Also I have one slight improvement:

      In my BaseController I added the following method

      import AppComponent from "../Component";
      
      ...
      
      getOwnerComponent(): AppComponent {
          return (super.getOwnerComponent() as AppComponent);
      }

      This way you don't have to assert the type, for example when doing getRouter or getContentDensityClass or getModel.

      Also this helper method might be helpful to some:

      getCurrentRoute(): string {
          const router = this.getRouter();
          const info = router.getRouteInfoByHash(router.getHashChanger().getHash());
          return (info as Record<string, unknown>).name as string;
      }
      Author's profile photo Wouter Lemaire
      Wouter Lemaire
      Blog Post Author

      Hi Marc,

      It's better to use the same as in the api.

       

      Please, feel free to add them to the repo by creating a pull request: https://github.com/lemaiwo/TypeScriptServiceDemoApp/

      Thank you!