Jpsy
Jpsy

Reputation: 20852

Show counter / index in SAPUI5 List Control through XML view

Is there a way to access an internal counter or index property of list items in an XML view, while iterating over the items of a SAPUI5 List control? The use case could be to simply enumerate the items. Or in my case it would be to give a special treatment to the very first list item.

What I am looking for is something like the hypothetical $counter in the following example:

  <List items="{MyModel>/MyRootElement}">
    <items>
      <CustomListItem>
        <Text text="This is element number {MyModel>$counter}." />
      </CustomListItem>
    </items>
  </List>

I know I can solve this using JS in the controller. But I would be interested in a pure XML solution.

Upvotes: 1

Views: 3708

Answers (2)

Serban Petrescu
Serban Petrescu

Reputation: 5206

Based on my knowledge, there is no built-in "pseudo-property" that would contain the index of the element. If we especially think about sorting, then I would imagine that there would be developers wanting the numbering to reflect the sorting and other developers wanting it to be stable with regards to sorting.

Nevertheless, in some concrete cases, it is possible to actually number your rows using a pure XML solution.

If the MyRootElement is an array, you could always do something like (working fiddle):

<List items="{/MyRootElement}">
    <StandardListItem title="{name}" 
        counter="{= ${/MyRootElement}.indexOf(${}) + 1 }" />
</List> 

If it is an object (i.e. a map-like structure) then you will need to use the Object.values() function. It provides the correct numbering because it is guaranteed to give the values in the same order as a for .. in loop which is actually used by the Model to create the bindings and ultimately the list items. It should be noted that the Object.values() function is not supported in IE and might require a polyfill. Example (and working fiddle):

<List items="{/MyRootElement}">
    <StandardListItem title="{name}" 
        counter="{= Object.values(${/MyRootElement}).indexOf(${}) + 1 }" />
</List>

Later edit: Binding path explanation

In the code samples, I have used the ${} construct to access the current, unnamed model's binding context's data object.

The rules related to building the binding paths are the following (as specified in the documentation):

  • The model name followed by a > sign. If this part is skipped, then the unnamed (default) model is used. The rest of the path after the > sign is used to find the referenced data inside the model.
  • If the path starts with a /, then it is an absolute path (the referenced data lookup is performed from the root object of the model). Otherwise, it is a relative path.
  • Relative paths are concatenated with the binding path of the nearest ancestor control which has a binding context for the model. If the resulting path is still relative, this is repeated recursively until an absolute one is obtained.
  • For JSON models, the path is split by the / sign and then the JSON object tree is traversed using the attribute names obtained from this split.

Concretely, in the case of ${}, the binding path itself is '' (an empty string). Using the rules above, this would be a relative path for the unnamed (default) model. As the path is empty, no attribute traversal is done (because there are no path components obtained after the path split).

Similarly, for named models, the ${MyModelName>} expression binding would have the same effect.

Upvotes: 5

I don't know about any counter in the table, however a workaround could be using a factory function and getting the row number fromt he row id:

Here the DEMO using Northwind and here the snippet:

<html>
	<head>
		<meta http-equiv='X-UA-Compatible' content='IE=edge'>
		<meta charset="utf-8">

		<title>MVC with XmlView</title>

		<!-- Load UI5, select "blue crystal" theme and the "sap.m" control library -->
		<script id='sap-ui-bootstrap'
			src='https://sapui5.hana.ondemand.com/resources/sap-ui-core.js'
			data-sap-ui-theme='sap_bluecrystal'
			data-sap-ui-libs='sap.m'
			data-sap-ui-xx-bindingSyntax='complex'></script>


		<!-- DEFINE RE-USE COMPONENTS - NORMALLY DONE IN SEPARATE FILES -->

		<!-- define a new (simple) View type as an XmlView
		 - using data binding for the Button text
		 - binding a controller method to the Button's "press" event
		 - also mixing in some plain HTML
		 note: typically this would be a standalone file -->

		<script id="view1" type="sapui5/xmlview">
		<mvc:View xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" controllerName="my.own.controller">
			<Page>
  			<Table items="{path:'/Orders', factory: '.createRow'}">
          <columns>
              <Column>
                  <Text text="#"/>
              </Column>
              <Column>
                  <Text text="Order ID"/>
              </Column>
          </columns>
        </Table>
			</Page>
		</mvc:View> 
    </script>


		<script>
			// define a new (simple) Controller type
			sap.ui.controller("my.own.controller", {
			  createRow: function (sId, oContext) {
			    console.log(sId);
			    console.log(oContext);
			    
			    var rowNumber = sId.split("-")[sId.split("-").length-1];
			    
			    var oRow = new sap.m.ColumnListItem({
            cells: [
              new sap.m.Text({
                text: rowNumber
              }),
              new sap.m.Text({
                text: {path: "OrderID"}
              })
            ]
          })
          
          return oRow;
      	}
			});
			
			
	
			/*** THIS IS THE "APPLICATION" CODE ***/
			// create a Model and assign it to the View
			// Using here the HEROKU Proxy to avoid a CORS issue
			var uri = "https://cors-anywhere.herokuapp.com/services.odata.org/Northwind/Northwind.svc"; // local proxy for cross-domain access
			var oNorthwindModel = new sap.ui.model.odata.ODataModel(uri, {
				maxDataServiceVersion: "2.0"
			}); 
			// instantiate the View
			var myView = sap.ui.xmlview({viewContent:jQuery('#view1').html()}); // accessing the HTML inside the script tag above
			// Set the OData Model
			myView.setModel(oNorthwindModel);
			
			
			myView.placeAt('content');
		</script>
	
	</head>
	<body id='content' class='sapUiBody'>
	</body>
</html>

Upvotes: 0

Related Questions