2

Let's imagine I have a class

sap.ui.core.Control.extend("sap.my.MyButton", {
    metadata: {
        properties: {                
            "isButtonWithMenu": {
                type: "boolean",
                defaultValue: true
            }
        }
    }
},

init: function () {
    if (this.getIsButtonWithMenu()) {
         this.myButton = this._createMenuButton();
    } else {
         this.myButton = this._createNormalButton();
    }
    var baseBox = new sap.m.FlexBox();
    baseBox.addItem(this.myButton);
    this.setLayout(baseBox);
}

Now I want to pass the value for isButtonWithMenu into my init method and I do the following:

var myButton = new sap.my.MyButton({isButtonWithMenu: false});

but this doesn't work which means that I don't get passed value inside the class. However, when I change defaultValue it does work, so, what is wrong in here and how I can achieve my target?

Jaro
  • 1,757
  • 1
  • 15
  • 36
Rufi
  • 2,529
  • 1
  • 20
  • 41
  • Where is the variable isButtonWithMenu set? – matbtt Jun 08 '17 at 10:11
  • I set it to false is during object creation. As I understand it should be applied behind the scenes and set the property to the correct value, am I wrong? – Rufi Jun 08 '17 at 10:32

1 Answers1

4

Your problem is caused by the code here in the ManagedObject's constructor. This class is a superclass of any control (ManagedObject <-- Element <-- Control). If you look into the code you will notice the the following steps occur:

  • An empty property bag is constructed (actually with your default values).
  • The control's init method is called.
  • The mSettings property bag is applied to your control. This property bag is the one that you (or the XML view parser) pass in the controls constructor.

This is the designed behavior for UI5. Because the init function should bring the control in an initialized state and only afterwards will the properties (passed to the constructor) be applied to your control. This ensures that whatever setters you have redefined are always called after the control was initialized (well, at least except the situation in which you call them inside the initialization code).

To get around this you have two options that I can think about:

  • Use the 0 delayed call trick (see What is setTimeout doing when set to 0 milliseconds? for explanations). Basically you can do: jQuery.sap.delayedCall(0, this, function() { this.myButton = ... }) to ensure that the settings were already applied to your control.
  • Define a constructor method for your control. Something along the lines of:
 sap.ui.core.Control.extend("sap.my.MyButton", {

    metadata: { /* same as before */},

    constructor: function () {
        sap.ui.core.Control.apply(this, arguments);

        // the init function was already called by this point
        // also the settings should have been applied

        if (this.getIsButtonWithMenu()) {
             this.myButton = this._createMenuButton();
        } else {
             this.myButton = this._createNormalButton();
        }
        var baseBox = new sap.m.FlexBox();
        baseBox.addItem(this.myButton);
        this.setLayout(baseBox);

    }
})

You can also put your code before the super constructor call (not really correct from an OOP perspective), but then you cannot use the getter and should look inside the mSettings constructor parameter (2nd param) instead.

Serban Petrescu
  • 5,127
  • 2
  • 17
  • 34