How to bind items to a sap.m.table in JS with correct use of template

Viewed 2487

I am trying to bind items to a sap.m.table in JS. XML binding does not allow dynamic filtering so this is not an option.

The scenario is quite basic: First screen is a list view. Second screen is a detail view for the selected entry of the list view. The detail view contains a table with additional information and in each line the user can select one of two radio buttons and hit an action button to perfom the selected action. Information which radio button is enabled and pre-selected is also returned from the backend and read from the model. The model has two-way-binding to reflect and react to user changes in the context but nothing is ever written back to the backend.

I would like to run the following code in the _onObjectMatched() after an entry was clicken on the first screen.

oTable.bindItems({
   path: 'Model>/pathToEntitySet',
   filters: aFilter,
   factory: function(sId, Context) { return that.byId('template').clone(sId);
   templateShareable: false,
   parameters: {
      'expand': 'anotherPath'
   }
});

The template is defined in XML as of the table:

<core:FragmentDefinition
  xmlns:core="sap.ui.core"
  xmlns="sap.m"
  xmlns:l="sap.ui.commons.layout"
  xmlns:table="sap.ui.table"
  xmlns:semantic="sap.m.semantic">
      <Table
        id="table"
        alternateRowColors="true">
        <columns>
            ...
        </columns>
        <dependents>
            <ColumnListItem id="template">
                <cells>
                    ...
                    <FlexBox>
                        <RadioButtonGroup columns="2" selectedIndex="{Model>SelectedAction}">
                            <RadioButton 
                                enabled="{= ${Model>isPos1}}"
                                text="{i18n>doThis}"/>

                            <RadioButton
                                enabled="{= ${Model>isPos2}}"/>
                        </RadioButtonGroup>
                        <ComboBox
                            items="{
                                path: 'Model>anotherPath',
                                templateShareable: false
                            }"
                            selectedKey="{Model>SelectedKey}"
                            enabled="{= ${Model>isPos2}}">
                            <core:ListItem key="{Model>Tey}" text="{Model>Text}"/>
                        </ComboBox>
                        <Button id="actionButton" 
                                press="onActionButtonPress" 
                                enabled="{= ${Model>isPos1} || ${Model>isPos2}}"
                                icon="sap-icon://begin"/>
                        <Label text="{Model>SelectedAction}"/> <!--Just for debugging purpose-->
                    </FlexBox>
                </cells>
            </ColumnListItem>
        </dependents>
      </Table>
</core:FragmentDefinition>

The first time I select an entry on screen one everything is loaded correctly. First Loading

Then I go back and click on the same line again and suddenly all values for Model>SelectedAction are displayed as -1. I can see in the Browser network analysis that the response is correct from the backend but somehow everything turns into -1 in the frontend. Second Loading

I finally managed to fix this by adding these two lines before oTable.bindItems({}). I would have expected that unbinding manually is not required before binding changes. Also I don't understand why I have to reset the model (two-way-binding) even if I did not do any change like selecting another radio button.

oTable.unbindItems();
this.getView().getModel("Model").resetChanges();

The detail page still behaves funny. I cannot select a radio button. Instead when I click on a radio button they disappear for a millisecond and just appear again. I could fix this by replacing the factory with a template in the binding function:

oTable.bindItems({
   path: 'Model>/pathToEntitySet',
   filters: aFilter,
   template: that.byId("template").clone(),
   templateShareable: false,
   parameters: {
      'expand': 'anotherPath'
   }
});

This code seems to be working but I am not having a good feeling about it. Feels not very stable. E.g. why cant UI5 take care of cloning my template? If I am not cloning it manually, a missing template error will be thrown the second time I open the detail view. And why do I have to unbind the items manually and reset the model?

Can you give some feedback if I am doing something fundamentally wrong or if this is actually the way how it is supposed to work?

0 Answers
Related