2
votes

I have been familiarizing myself with OpenUI5 for quite a few weeks now and I keep facing new problems like the one I am now asking a question about. As I always do, I did my homework properly - looking for a solution, documentations, similar threads, etc.

What I want to achieve: I want to display a sap.m.ComboBox within one of the columns of a sap.ui.table.Table and bind it to the corresponding value for the current row. They should be able to alter the value for a particular row by SelectionChanging it.

What is my progress so far: I am using a standard $.ajax(); call to populate a model like this:

oModel = new sap.ui.model.json.JSONModel();
oModel.setData(dataToShow); // dataToShow being an array of entities

For simplicity, let each of those entities in dataToShow look like this:

{
    itemID: '123',
    state: 1 // state is an int column in the database
}

So each entity has a property 'state' of type int. I create an ordinary oTable like this: oTable = new sap.ui.table.Table({...});

The 'itemID' column is defined like this:

oTable.addColumn(new sap.ui.table.Column({
    label: new sap.ui.commons.Label({ text: "Number of item" }),
    template: new sap.ui.commons.TextView({ text: "{itemID}" }),
    sortProperty: "itemID", // https://sapui5.netweaver.ondemand.com/sdk/test-resources/sap/ui/table/demokit/Table.html#__2
    filterProperty: "itemID",
    width: gridTestColWidth
}));

For the second column, I try to put a ComboBox inside it like this:

// first, hard-code (for now) the list of possible items
var cbStateItems = [
    {
        Code: 0,
        //Code: '0', // I tried to set the number as string, which didn't affect the situation in any way
        Name: "test1",
        AdditionalText: "test11"
    },
    {
        Code: 1,
        Name: "test2",
        AdditionalText: "test22"
    },
    {
        Code: 2,
        Name: "test3",
        AdditionalText: "test33"
    }
];
var cbStateModel = new sap.ui.model.json.JSONModel({ items: cbStateItems });

var cbStateTemplate = new sap.ui.core.ListItem({
    key: "{Code}",
    text: "{Name}",
    additionalText: "{AdditionalText}"
});

var cbState = new sap.m.ComboBox({
    // here, all commented lines - I tried to uncomment one or couple of them at a time in different groups of uncommented lines to test (first, first and second, etc.)
    //text: '{state}',
    //selectedKey: '{state}',
    items: {
        path: '/items',
        template: cbStateTemplate,
        //selectedItemId: '{state}',
        templateShareable: false
    },
    showSecondaryValues: true,
    //selectedItemId: '{state}',
    //selectedKey: '{state}',
    //key: '{state}',
    //value: "{Name}",
    selectedKey: function (key) {// here, I thought, that maybe I can implement the binding manually. I know, that this is a prop of type string, but thought, that I could pass it a function, that returns a string - does not get called
        debugger;
        if (typeof (key) !== 'undefined' && key !== null) {
            return cbStateItems[key].Name;
        } else {
            return '0';
        }
    },
    selectionChange: function (oControlEvent) {
        var gewrgter = oModel;
        debugger;
    }
}); //.bindProperty("selectedKey", "state"); //.bindProperty("selectedItemId", "state"); none of those work
debugger;
cbState.setModel(cbStateModel);

var cbStateCol = new sap.ui.table.Column({
    label: new sap.ui.commons.Label({ text: "State" }),
    template: cbState,
    width: gridTestColWidth
});
oTable.addColumn(cbStateCol);

Finally, I call oTable.setModel(oModel); to show the data in the grid.

The data I get from the database contains the values null, 0, 1 or 2 within the column 'State' for all the entities.

The main problem: None of the rows in the oTable has anything selected in the State column and the ComboBox inside it, although all of them have a non-null value(actually, only the first row in the database table has null as a value in the column State)

Everytime I test this (with different rows uncommented), I see one of two scenarios after the data is successfully loaded in the oTable:

  1. When I selectionChange the value for one row, it's 'Name' property's value gets displayed as text in the textbox part of the ComboBox control. But when I scroll down the rows, it looks like this value is 'stuck' to the, say 3rd row. When I scroll once (4 rows at a time), the selectedValue (let it be 'test33') goes away of the row, where I made the selectionChange and becomes the 'selected' value in the ComboBox of the 4th row after this one. If I scroll again, this value 'test33' sort of 'moves down' another 4 rows. When I expand the ComboBox, I see, that the highlighted item is the one I selected.
  2. If I uncomment, for example, this row: selectedItemId: '{State}', make a selectionChange, nothing is displayed in the textbox portion of the ComboBox, although the selected item is highlighted as 'selected'.

I am totally confused now, since I was expecting, that selectedItemId: '{State}' or selectedKey: '{State}' are going to do the 'binding' job for me, but they seem not to. Thank you in advance for your help and pieces of advice!

2

2 Answers

2
votes

When you are using multiple data models it's always a better approach to use named models. This may resolve multi-model issues with you application. Here is a way to do it with XML Views

<mvc:View
controllerName="com.sap.app.controller.Detail"
    xmlns:mvc="sap.ui.core.mvc"
    xmlns:core="sap.ui.core"
    xmlns:table="sap.ui.table"
    xmlns="sap.m">
    <Page title="Detail section">
        <table:Table 
        rows="{tableModel>/items}">
        <table:columns>
            <table:Column>
                <Label text="Item ID" />
                <table:template>
                    <Text text="{tableModel>itemID}"/>
                </table:template>
            </table:Column>
            <table:Column>
                <Label text="State" />
                <table:template>
                    <ComboBox
                        selectedKey="{tableModel>state}"
                        items="{cbState>/items}">
                        <core:Item key="{cbState>Code}" text="{cbState>Name}" additionalText="{cbState>AdditionalText}"/>
                    </ComboBox>
                </table:template>
            </table:Column>
        </table:columns>
    </table:Table>
    </Page>
</mvc:View>

Controller code:

    var oTabDataset = [
            {
                itemID: '123',
                state: 1
            },
            {
                itemID: '255',
                state: 2
            },
            {
                itemID: '326',
                state: 3
            },
            {
                itemID: '456',
                state: 4
            }
        ];
        var oTableModel = new JSONModel({ items: oTabDataset });
        this.getView().setModel(oTableModel, "tableModel");

        var cbStateItems = [
            {
                Code: 0,
                Name: "test1",
                AdditionalText: "test11"
            },
            {
                Code: 1,
                Name: "test2",
                AdditionalText: "test22"
            },
            {
                Code: 2,
                Name: "test3",
                AdditionalText: "test33"
            },
            {
                Code: 3,
                Name: "test4",
                AdditionalText: "test44"
            }
        ];
        var cbStateModel = new JSONModel({ items: cbStateItems });
        this.getView().setModel(cbStateModel, "cbState");
0
votes

I post this in case it is of use though it feels a bit flimsy compared to the quality of a @Matbtt or @Qualiture response.

The select box has a .setSelectedItem() function that requires as input a select list item. In this code I get a select list from the view, get its first entry and make it selected.

var oSelect = this.getView().byId("SubsSelect")
var oFirstItem = oSelect.getItems()[0];  // I only need to get the first - you may care to iterate the list and match keys to the row etc.
oSelect.setSelectedItem(oFirstItem)
oSelect.fireChange(firstItem) // I then invoke the change event to kick off some code.

Not a direct match to your needs but might be of help.