Search code examples
sapui5

SAP UI5 issue, render Calling two time in Custom Control


In view

var oData = {
        "SavedSearch" : [
            {   name : "Save1" },
            {   name : "Save2" },
            {   name : "Save3" },
            {   name : "Save4" },
            {   name : "Save5" }
        ]
    }
    var oModel = new sap.ui.model.json.JSONModel();
    oModel.setData(oData);
    sap.ui.getCore().setModel(oModel,"ModelData");
    var oTest = new test({
        manageSavedSearch :{
                path    : "ModelData>/SavedSearch",
                template: new sap.ui.commons.Button({
                    text : "{ModelData>name}"
                })
        },
    });
    oTest.placeAt(this);

In Custom Control

sap.ui.core.Control.extend("test",{
metadata:{
    properties : {},
    aggregations:{      
        manageSavedSearch   :   {type : "sap.ui.commons.Button", multiple :true },
        layout              :   {type : "sap.ui.layout.VerticalLayout", multiple :false }
    }
},
init : function(){
},
renderer : {
    render : function(oRm, oControl) {
  // Come two Times  Here
        var manageSavedSearch = oControl.getManageSavedSearch();
        var oSavedButtonHLyt = new sap.ui.layout.VerticalLayout();
        for(var index = 0 ; index < manageSavedSearch.length ; index++){
            oSavedButtonHLyt.addContent(manageSavedSearch[index]);
        }
        oControl.setAggregation("layout",oSavedButtonHLyt);
       oRm.renderControl(oControl.getAggregation("layout"));
    }
  }
},
onAfterRendering: function(){}
});

If I don't use any layout then It doesn't come two time in render otherwise it comes two time in render. This issues is happening from version 1.24.4. please Can I have any guidance here.


Solution

  • Changing aggregation(e.g. add/remove/insert/set/removeAll) invalidates the control. You should never invalidate a control during the rendering. In your case it can be an infinite loop.

    To debug rendering invalidation there is a url parameter test.html?sap-ui-xx-debugRendering=true then you can see the rendering stack trace and who is responsible for the rendering.

    In your code sample, there are two aggregations update. setAggregation and addContent. Aggregation mutatators uses 3rd parameter to suppress invalidation. So following will insert the aggregation but suppress the invalidation since whole control will be rendered at the end it will not be a problem.

    oControl.setAggregation("layout",oSavedButtonHLyt, true); // suppress invalidate
    

    I guess you assume same should work for addContent

    oSavedButtonHLyt.addAggregation("content", manageSavedSearch[index], true);
    

    But it does not because here manageSavedSearch[index], so your template clone's parent is oTest initially, but you are changing the parent with addAggregation because layout will be the parent. But UI5 cannot determine automatically for the previous parent's suppress since its aggregation will be moved to somewhere else. So we go with

    oControl.removeAggregation("manageSavedSearch", manageSavedSearch[index], true);
    oSavedButtonHLyt.addAggregation("content", manageSavedSearch[index], true);
    

    Here is the jsbin http://jsbin.com/rezayebada/1/edit?js,output

    BTW, as you mentioned this is just an example do not take this as a reference for building composite controls.

    Basically, property/aggregation/association changes invalidates the control if the control does not overwrite its mutator methods. I see it is not easy to understand what invalidates when but sap-ui-xx-debugRendering=true helps you to understand with stack trace.