Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Missing template or factory function for aggregation items of Element" while Binding Items Dynamically

Tags:

sapui5

I am trying to bind items in a sap.m.Table (preventing usage of a Factory function) and I am getting this error:

Missing template or factory function for aggregation items of Element

My views looks as follows:

<Table id="favTable">
  <headerToolbar>
    <Toolbar>
      <Title id="tableHeader" text="{i18n>tableHeader}"/>
    </Toolbar>
  </headerToolbar>
  <columns>
    <Column>
      <Label text="{i18n>serviceNameColText}" />
    </Column>
    <Column>
      <Label text="{i18n>serviceTechNameColText}"/>
    </Column>
    <Column width="50px"/>
  </columns>
  <ColumnListItem>
    <Text text="{Text}" />
    <Text text="{Service}" />
    <Button icon="sap-icon://delete" press="onDeleteRow" />
  </ColumnListItem>
</Table>

According controller code (using a bound OData service) tries to bind items into the view after the route has been hit:

_onPatternMatched: function(oEvent) {
  let oTable = this.getView().byId(sIdTable);
  // bind items dynamically with attributes
  const sGroupId = oEvent.getParameter("arguments").Group;
  let sBindingPath = "/DataSet(SetId='" + sSetId + "')"
  oTable.bindItems({
    path: sBindingPath,
    parameters: {
      navigation: {
        FavoriteGroupSet: "ToFavorites"
      }
    },
    filters: [
      // new Filter("InstitutionId", "EQ", oEvent.getParameter("arguments").Institution),
      new Filter("SetId", "EQ", sSetId)
    ]
  })
},

What do I need to do to make the correct binding to show up the correct data?

like image 878
Pille Avatar asked Mar 28 '18 14:03

Pille


1 Answers

In UI5's concept of aggregation binding, you can use two mechanisms to build the aggregation items:

  • Template elements, which are cloned for each individual item from the model collection.
  • Factory functions, which are called for each individual item from the model and are expected to build a new control / element for each call.

I would assume that you want to use the ColumnListItem from your XML as a template. The problem is that when building XML views, controls are used as templates for the parent aggregation only when you also bind the parent aggregation in XML as well. Otherwise, they are interpreted as simple children.

In a nutshell, UI5 interprets your view as if you have a sap.m.Table with a single, static item. When you try to bind the items aggregation later, it destroys this item (well, actually it just throws an error in your case, as you must specify either a template or a factory when you use the bindAggregation method (bindItems is just a wrapper for this method).

One option to correct this would be to use relative binding and then use the bindElement method instead to change the Table's binding. In your case, it is not really clear what you want to do, as the sBindingPath seems to have a value like /DataSet(SetId='ABC'), which actually will not point towards a collection, but towards a single DataSet entity.

If you actually change the way in which your OData service is used and you have a navigation (e.g. the path would look something like /DataSet('ABC')/MyNavigationSet), then you can do the following:

View:

<!-- note that the items binding path should not start with / (to be relative) -->
<Table id="favTable" items={MyNavigationSet}>
    <columns>
        <!-- your columns... -->
    </columns>
    <items>
        <ColumnListItem id="favTableItemTemplate">
            <cells>
                <Text text="{Text}" />
                <Text text="{Service}" />
                <Button icon="sap-icon://delete" press="onDeleteRow" />
            </cells>
        </ColumnListItem>
    </items>
</Table>

Controller:

function(oEvent) {
    // the rest of your code
    this.byId("favTable").bindElement(sBindingPath);
}

Another option which works with your current OData service is to declare your template as a dependent and then use it for the binding. The templateShareable flag should be set such that the template is not destroyed on re-binding the aggregation.

View:

<Table id="favTable">
    <columns>
        <!-- your columns... -->
    </columns>
    <dependents>
        <ColumnListItem id="favTableItemTemplate">
            <cells>
                <Text text="{Text}" />
                <Text text="{Service}" />
                <Button icon="sap-icon://delete" press="onDeleteRow" />
            </cells>
        </ColumnListItem>
    </dependents>
</Table>

Controller:

function(oEvent) {
    // the rest of your code
    this.byId("favTable").bindItems({
        path: sBindingPath,
        template: this.byId("favTableItemTemplate"),
        templateShareable: true,
        parameters: {
            navigation: {FavoriteGroupSet: "ToFavorites"}
        },
        filters: [new Filter("SetId", "EQ", sSetId)]
    })
}
like image 58
Serban Petrescu Avatar answered Oct 22 '22 00:10

Serban Petrescu