Search code examples
sapui5

Writing SAPUI5 control renderer in "sap.ui.define" style


I'd like to write custom control in a new sap.ui.define fashion. I have a problem implementing control renderer in a separate file: it seems one have to put bExport = true, while this is forbidden by SAP.

bExport: whether an export to global names is required - should be used by SAP-owned code only

I haven't found any examples of renderer implementations that doesn't utilize export hack and I have a doubt if such a way ever exists.

I've got some suggestions, but they doesn't fully satisfy me:

  • Ignore SAP requirement and use bExport = true. Pros: highest reuse of SAP code and generally follow standard logic. Cons: avoiding official recommendations.
  • Explicitly set my.namespace.control.GreatControlRenderer from within factory function. Pros: simple, doesn't touch bExport. Cons: breaks modular design (as module actually sets global variable).

What is the best or recommended way to resolve this issue?


Technically, an object reference available for public use is created inside framework code with jQuery.sap.setObject method, both in:

  1. sap.ui.core.Control.extend() -- actually within parent class method sap.ui.base.Metadata.createClass()
  2. sap.ui.define(/* bExport = */ true)

This method creates hierarchy of objects in global scope by object dot.separated.qualified.name as follows:

jQuery.sap.setObject = function(sName, vValue, oContext) {
  var oObject = oContext || window,
      aNames = (sName || "").split("."),
      l = aNames.length,
      i;

  if (l > 0) {
    for (i = 0; oObject && i < l - 1; i++) {
      if (!oObject[aNames[i]]) {
        oObject[aNames[i]] = {};
      }
      oObject = oObject[aNames[i]];
    }
    oObject[aNames[l - 1]] = vValue;
  }
};

Solution

  • First, your Renderer is an Object with a render function. It's a static function. Return this Renderer from your module.

    sap.ui.define([], function(){
      "use strict";
      var MyControlRenderer = {};
      MyControlRenderer.apiVersion = 2;
      MyControlRenderer.render = function(oRm, oControl){
        // Render your control
      };
      return MyControlRenderer;
    });
    

    Then in your control, you import your Renderer object and assign it to the renderer property of your control like this:

    sap.ui.define([
      "sap/ui/core/Control",
      "./MyControlRenderer"
    ], function(Control, MyControlRenderer) {
      "use strict";
      var MyControl = Control.extend("bla.MyControl", {
        metadata: {
          // ...
        },
        renderer: MyControlRenderer
      });
      return MyControl;
    });
    

    In this example the renderer is in the same directory as the control.