1

I'm trying to get UI5 to change the row backgound based on the value of a field. This works after the initial load has been done and you scroll, but it doesn't work on the initial load.

This isn't working because the cell hasn't been added to its parent container as far as I can tell this.$().closest('tr') returns nothing. Upon scrolling the cell has been added to its parent, and then everything woks just fine.

<!DOCTYPE html>  
<html><head>  
    <meta http-equiv='X-UA-Compatible' content='IE=edge' />  
    <title>Bindign Rows</title>  

    <script id='sap-ui-bootstrap' 
        src='https://openui5.hana.ondemand.com/resources/sap-ui-core.js'  
        data-sap-ui-theme='sap_bluecrystal'  
        data-sap-ui-libs='sap.ui.commons,sap.ui.table'></script>   

    <script>  
       var data = [
           {sex: 'm', fname: 'XXX' , lname : 'YYYYY'},
           {sex: 'm', fname: 'XXX' , lname : 'YYYYY'},
           {sex: 'f', fname: 'XXX', lname : 'YYYYY'},
           {sex: 'f', fname: 'XXX', lname : 'YYYYY'} ,
           {sex: 'm', fname: 'XXX', lname : 'YYYYY'},
           {sex: 'f', fname: 'XXX', lname : 'YYYYY'}
       ];

       var oTable = new sap.ui.table.Table({visibleRowCount: 3});
       var oModel = new sap.ui.model.json.JSONModel();
       oModel.setData({modelData: data});
       oTable.setModel(oModel);

       var template1 = new sap.ui.commons.TextField().bindProperty("value", "sex", 
           function(sex){
              if(sex == "m" ){
                  //  !! the below parent can't be found.
                  this.$().closest("tr").css("background-color", "red");            
              }  else  if(sex == "f" )
              {  
                  this.$().closest("tr").css("background-color", "inherit");
              }
              return sex ;
            }
        );

        oTable.addColumn(new sap.ui.table.Column({ label: "Sex",
                                             template:  template1}));

    oTable.placeAt('content');  
    oTable.bindRows("/modelData");
</script>

</head>
<body class='sapUiBody'>
    <div id='content'></div>
</body>
</html>

What you'll see is that upon initial load all cells are grey.

When you scroll all cells with sex:M will get a red background. We'd love it if the red background would populate right from the first load.

enter image description here

JsBin link


Things we tried:

  • Supplying the template to the call to .bindRows('/data', template1), it seems that the type of template to supply to this call is a different one, but hardly documented on the SAP website.
  • Calling bindRows twice.
  • WORKAROUND: >>> doing the styling on a timer, works but is ugly and not stable enough.
  • I can't find a onParentChanged handler, onLoad or similar event that triggers after the data has been bound and I can't find an event akin to thd onDataBinding vs onRowCreated that I'm used to from my .NET background.
  • Just changing the style of the textbox itself works as is to be expected.
jessehouwing
  • 106,458
  • 22
  • 256
  • 341
  • Would this related question help? http://stackoverflow.com/questions/22704644/how-to-change-the-color-of-row-in-table-sapui5 – Qualiture May 16 '14 at 01:44
  • Yes it seems related. Thing is that the onAfterRendering works for the first table we draw, but the page fetches new data using an Ajax call and the coloring fails for the second table... Will try to piece a second job je together that shows that behavior. – jessehouwing May 17 '14 at 10:09

2 Answers2

2

Better Solution

Combined addDelegate with the scroll handler on the vertical scrollbar, not ideal because they are both undocumented features

function updateRows(oEvent) {
    if (oEvent.type !== 'AfterRendering'){
      this.onvscroll(oEvent);
    }
    var rows = this.getVisibleRowCount();   //number of rows on tab
    var rowStart = this.getFirstVisibleRow();
    var ctx;
    for (var i=0; i<rows; i++){
       ctx = this.getContextByIndex(rowStart + i); //content
       this.getRows()[i].$().toggleClass("male",ctx?ctx.getObject().sex === 'm':false);
    }
};

oTable.addDelegate({ onAfterRendering : $.proxy(this.updateRows, oTable)});
oTable._oVSb.attachScroll(this.updateRows,oTable); 

see updated jsBin example

jessehouwing
  • 106,458
  • 22
  • 256
  • 341
Jasper_07
  • 2,453
  • 2
  • 18
  • 23
  • The Scroll event does do the coloring correct, but breaks the scroll bar when using the Scroll wheel. It also break things like dragging the scroll indicator to the top of the screen (it doesn't show the top most item in the table every time). Unhooking the scroll event fixes that. – jessehouwing May 19 '14 at 10:31
  • there was an existing scroll handler that got overwritten, have added it back see above and jsBin – Jasper_07 May 19 '14 at 11:06
  • Horrible though it looks, it seems to do the job :). – jessehouwing May 19 '14 at 11:13
  • We still combined it with the timer Solution for the best overall stability... I thought this Javascript framework would be cool and easy... – jessehouwing May 19 '14 at 17:27
  • Agreed, and definitely something that should be possible in a cleaner, out of the box solution in a future version. But for now I'll take this solution too as the current way forward, thanks for looking into this! – Qualiture May 20 '14 at 01:24
0

WORKAROUND

Introducing a timer seems to work around the issue. I find it a very ugly solution and I'd prefer a better one, at least this seems to get us unstuck. Very much open to a better solution:

var template1 = new sap.ui.commons.TextField().bindProperty("value", "sex", 
  function(sex){
    var changeRow =  function(cell)
    {
      var row =  cell.$().closest("tr");
      if (row != undefined)
      {
        if(sex == "m" ){
          row.css("background-color", "red");            
        } 
        else
        {  
          row.css("background-color", "inherit");
        }
      }  
    };

    var row =  this.$().closest("tr");
    if (row.length != 0)
    {
      changeRow(this);
    }   
    else
    {
      // might need to increase the timeout. in the demo 150ms seems to be enough.
      window.setTimeout(changeRow, 150, this);
    }
    return sex ;
  }
);
jessehouwing
  • 106,458
  • 22
  • 256
  • 341
  • So far, this combined with the `oTable.addDelegate({ onAfterRendering : $.proxy(this.updateRows, oTable)});` seems to be the most stable solution... – jessehouwing May 19 '14 at 10:34