MultiComboxBox within a table closes after selection - sapui5

I have tried to resolve the problem for quite sometime but have not been successful.
Inside a table, I have a sap.m.MultiComBox. The drop down in the multicombobox closes after selecting the first value. If not inside the table, the multicombobox works fine as expected (popover does not close). One additional behavior I observed is that if I don't have the selectedKeys bound, then it works fine.
Any reasons or suggestions?
<Table
growing="true"
items="{employee>/EmployeeCollection}">
<columns>
<Column width="10%" />
<Column width="55%" />
<Column width="35%"/>
</columns>
<ColumnListItem>
<Image id="image" src="{employee>dataURI}" class="sapOB_Assign_Usercircle" />
<Text text="{employee>Name}" class="tableText" />
<VBox>
<MultiComboBox id="mcb1"
selectedKeys="{employee>roles}"
items="{
path: 'roles>/BusinessRoles',
templateShareable: false
}">
<core:Item key="{roles>id}" text="{roles>name}" />
</MultiComboBox>
<HBox />
</VBox>
</ColumnListItem>
</Table>

You must be using UI5 version 1.66 or below with growing="true" on the Table. In that case, the dropdown closes immediately after the selection due to a focus loss caused by rerendering of the list item (Its DOM element being rewritten completely). The rerendering itself is caused by two-way bound selectedKeys which explains why it "works" if the property is not bound.
Normally, two-way binding should not be used together with growing. According to the API reference:
Note: Growing must not be used together with two-way binding.
But it's still unclear whether the above constraint is still valid today (See issue #3013).
In order to keep two-way binding with growing="true", add the attribute key* to the list binding info:
<Table
growing="true"
items="{
path: 'employee>/EmployeeCollection',
key: 'employeeId'
}"
>
Here is a working example: https://jsbin.com/ciyosir/edit?js,output. As you can see, the dropdown is kept open even after selection because the list item is not rerendered thanks to the extended change detection.
Additionally, I'd suggest to upgrade to the latest stable UI5 version in order to benefit from many controls having migrated to the new semantic rendering.
* The key awaits a property name from the model of which the value is unique. For more information, see topic Extended Change Detection.

Related

SAPUI5 Strange data binding behaviour

It's pretty silly problem but I have no idea why is it happening. I heve this in my controller:
this.getView().setModel(this.placesModel, "myCity");
then I set the data with Ajax request to my express RESTFull app and in View.xml
<List items="{path: 'myCity>/people'}">
<CustomListItem>
<VBox>
<Title text="Person:"/>
<Label text="{myCity>/people/name}"/>
<Label text="{myCity>/people/age}"/>
</VBox>
</CustomListItem>
</List>
I have object myCity with few properties. One of them is object people which is array of objects. When I try to list them like that I can see that all my people get listed but without corresponding name and age. Also I find it hard to understend when to use > when / when when >/.
Basic binding syntax with model name is {(model_name)>(path_to_property)}, if you don't have a model name (default model) you need to specify only {path_to_property}.
The initial slash (/) is needed if you don't have a contextbinding. In your case you have contextbinding set on List, so you don't need to use the slash.
Updated code:
<List items="{path: 'myCity>/people'}">
<CustomListItem>
<VBox>
<Title text="Person:"/>
<Label text="{myCity>name}"/>
<Label text="{myCity>age}"/>
</VBox>
</CustomListItem>
</List>
For more information refer to Binding Path.

How to make only one cell editable in smart table sapui5

I am using a sapui5 smart table to list down my products. It includes product code, product description and order quantity.
Among these three fields i want to update only the order quantity. It should be an inline editing in the table.
In my smart table i have enabled the property "editable" as "true". It makes the entire row is editable. Instead of making entire row editable, i want make only one cell to be editable.
Example
<smartFilterBar:SmartFilterBar id="smartFilterBar" entityType="ZDEMO_C_MyEntityType" persistencyKey="SmartFilter_Explored">
</smartFilterBar:SmartFilterBar>
<smartTable:SmartTable id="mySmartTable"
smartFilterId="smartFilterBar"
tableType="GridTable"
editable="true"
entitySet="ZDEMO_C_MyEntity"
useVariantManagement="false"
useTablePersonalisation="true"
header="My Products"
showRowCount="true"
useExportToExcel="true"
enableAutoBinding="true">
</smartTable:SmartTable>
I can see 2 ways:
Make use of "field controls" concept. It requires adding a special properties within your entity type, which define the state of the fields (cells). Also some annotations have to be introduced (in the metadata.xml by backend) to initiate the handling.
Here is a link where concept described using Form control as an example, but the same rules are applicable for Table as well:
https://blogs.sap.com/2017/06/06/dynamic-field-control-using-annotations-in-sapui5/
Redefine the table rows manually in your XML and bind the needed cell(s) against the property of the local JSON model, which could be changed depending on some conditions (e.g. Edit button press).
The 1st approach is better from the architectural perspective but requires some data model modifications (from the backend side).
The 2nd approach allows to do everything on UI and program some complex UI logic, which defines the cells state.
You choose.
You can add a sap ui table inside the smart table and add columns with customdata property. Follow these steps.
Make editable="true" as editable="false"
In your xml, make sure to add this namespace xmlns:core="sap.ui.core"
Within the smarttable tag add below.
<smartTable:SmartTable .................................
<Table>
<columns>
<Column>
<customData>
<core:CustomData key="p13nData" value='\{"columnKey": "OrderQty", "leadingProperty": "OrderQty", "columnIndex":"2"}'/>
</customData>
<Text text="Order Qty"/>
</Column>
</columns>
<items>
<ColumnListItem>
<cells>
<Input value="{OrderQty}" type="Number" editable="true"/>
</cells>
</ColumnListItem>
</items>
</Table>
</smartTable:SmartTable>
Add below tag inside table to make your column editable
<table:Column sortProperty="Max_Capacity" filterProperty="Max_Capacity" id="maxCapCol">
<Label text="Max Capacity"/>
<table:template>
<Input text="{Max_Capacity}" />
</table:template>
</table:Column>

SAPUI5/Fiori: Multiple Step Inputs in one View (Duplicate Id)

I'm developing an app in SAPUI5/Fiori and I want to implement the "Step Input" control in a table for each row.
In the explored reference of Fiori, I copied the control code, but I currently get the following error:
Core-dbg.js:2711 Uncaught (in promise) Error: Error: adding element
with duplicate id '[..]--stepInput-decrementBtn'
My View looks like this:
<Table id="lineItemsList" width="auto" items="{/itemsSet}"class="sapUiResponsiveMargin">
<headerToolbar>
<Toolbar id="lineItemsToolbar">
<Title id="lineItemsHeader" text="{/lineItemListTitle}"/>
</Toolbar>
</headerToolbar>
<columns>
<Column vAlign="Middle">
<Text text="{i18n>detailLineItemTableIDColumn}"/>
</Column>
<Column hAlign="Right">
<Text text="{i18n>detailLineItemTableUnitNumberColumn}"/>
</Column>
</columns>
<items>
<ColumnListItem>
<cells>
<Label id="label1" text="{itemID}"/>
<StepInput
id="stepInput"
value="0"
width="120px"
min="0"
max="15"
step="1"
editable="true"/>
</cells>
</ColumnListItem>
</items>
</Table>
I also tested to give the StepInput no id, but still the same error.
I have had a look at your problem. I did some tests based on the SAPUI5 example https://sapui5.hana.ondemand.com/explored.html#/sample/sap.m.sample.StepInput/preview
And found that the problems comes from the property editable which if it is manually set to true provokes the error you found.
You have several choices:
You don't put this attribute, the field will be editable and it will work
Match the value of the attribute to an element of your model (as in the example), it will work even when the value is true
Also you should create a ticket to SAP to raise this problem which is problem a standard issue.
Hope this'll help !
Almiriad is right, this is a freaking bug in the latest versions, you can see it by debugging StepInput-dbg.js >> the decrement button creation method is sent twice (because the 'setEnaditable' checks the aggregation and creates the button)
Since true is the default value for editable property, you dont need it here :)

How to enable scrolling in sap.m.Table in sapui5?

I have implemented sap.m.Table but all the records are not displayed. Also there seems to be no option for scrolling. I went through the API which suggests using growing, growingThreshold, growingScrollToLoad of sap.m.ListBase.
Here growing would enable the table control to load more items, growingThreshold would determine the number of items to be requested from the model for each grow and getGrowingScrollToLoad would enable the user to scroll through the records instead of a more button being displayed to load more data.
However, even after using these properties my entire data is still not getting rendered and I can see that more button instead of scroll bar. Below the more button I am able to see a number that determines the entire number of records to be rendered as well and the number of records that have been rendered in the initial view.
Shouldn't scrolling be a default option if the data exceeds a page's limit? I'm very confused. Please help.
Also I did go through this post! :)
Update 8-March-2019 :
There is now a new way to enable scrolling in sap.m.Table with sticky option.
Kindly check the API and samples for more example. This new way is recommended and support and development is provided directly via the library.
Check: https://sapui5.hana.ondemand.com/#/api/sap.m.ListBase/methods/setSticky
Old Answer:
Given how the question is beautifully setup, with options:
sap.ui.table.Table : scrollable with fixed Header.
sap.m.Table: growing list, scrollable WITHOUT fixed header.
But many a times we need a sap.m.Table- scrollable but with static header, so the content below the table does not move further below. This below code will help during that time. It has a scrollable body with fixed header.
Setup: I'm using two sap.m.Table instances, one just with header and other just for data. Also, I'm using a scrollable container, which holds the 2nd table (without the header). Because of the fixed width of Scrollable container, we see a scrollbar. Dummy code is provided below:
View.xml:
<Table showNoData='false'>
<columns>
<Column>
<header>
<Text text='ID' />
</header>
</Column>
<Column>
<header>
<Text text='First Name' />
</header>
</Column>
<Column>
<header>
<Text text='Last Name' />
</header>
</Column>
<Column>
<header>
<Text text='Gender' />
</header>
</Column>
</columns>
</Table>
<ScrollContainer height='20rem' vertical='true'> <!-- To have fixed with and enable vertical scrolling of data table -->
<!-- Table to hold data, data ,data -->
<Table class='tableHdr' items='{/}'> <!-- CSS class to hide the column header, otherwise we will have 2 headers. -->
<columns>
<!-- Dont need columns header, as upper table has already defined them. -->
<Column >
</Column>
<Column >
</Column>
<Column >
</Column>
<Column >
</Column>
</columns>
<items>
<ColumnListItem>
<cells>
<Text text='{id}' />
<Text text='{first_name}' />
<Text text='{last_name}' />
<Text text='{gender}' />
</cells>
</ColumnListItem>
</items>
</Table>
</ScrollContainer>
Now, If you execute the above code without this below style class, you will end up with 2 columns headers from 2 tables. So, to remove the 2nd Column header, I used the below class:
.tableHdr .sapMListTblHeaderCell {
padding: 0rem;
}
Would like to hear the feedback on this.
By default, if there are more rows in sap.m.Table, scrolling will be there.
You can see the working example here
But if you want to force to fixed rows visibility, you can use sap.ui.table.Table with the properties visibleRowCount and minAutoRowCount.
Also note that if the vertical scrollbar is not visible for sap.m.Table, check if some other css is overriding the style. Else you can paste the code in the question with full ui code.

How to handle the itemPress of sap.m.Table?

I've written an XML view. Inside it there is a table:
<Table xmlns="sap.m"
id="myTable"
select=""
selectionChange=""
swipe=""
growingStarted=""
growingFinished=""
updateStarted=""
updateFinished=""
itemPress="console.log('clicked on item')"
>
<columns>
<!-- sap.m.Column -->
</columns>
<items>
<!-- sap.m.ListItemBase -->
</items>
</Table>
I insert the row to the table using the onInit of the controller, but when I click on a row, the message is not shown.
If I use console.log(tablePippo.getProperty("itemPress")); inside the controller, it throws
Uncaught Error: Property "itemPress" does not exist in Element sap.m.Table#operationDetail--myTable
This really seems to be a frequent issue people face when they use sap.m.ListBase related controls. Let me give you an overview on how to manage the events (and particularly activate them at all):
The confusion could be related to the sap.m.ListMode of controls inheriting from sap.m.ListBase and the sap.m.ListType of items inheriting from sap.m.ListItemBase.
Let's assume the following sample List:
<List
selectionChange=".onSelectionChange"
itemPress=".onItemPress"
delete=".onDelete"
>
<items>
<ObjectListItem
title="Hello ListItem"
press=".onObjectListItemPress"
/>
</items>
</List>
sap.m.ListMode (Sample)
If you're using sap.m.List or sap.m.Table, event firing depends on the mode you're using. Unfortunately, a List / Table without a mode property will not fire any event from its side! If you want the List / Table to fire those events, you have to assign to it a mode. For example:
<List
mode="SingleSelect"
...
>
These are the possible modes from the sap.m.ListMode documentation:
None (default)
Since no mode property is assigned, none of the events will be fired!
SingleSelect | SingleSelectLeft
A list control with mode="SingleSelect" shows a radiobutton on the right side of each item and will fire the onSelectionChange event as soon as the user clicks on the given radio button control. Using "SingleSelectLeft" just moves the radio button to the left side of the item.
SingleSelectMaster
A list control with mode="SingleSelectMaster" will show you the hand on mouseover and fires the onSelectionChange in case of a click on an item.
MultiSelect
A list control in mode="MultiSelect" offers a checkbox and fires the onSelectionChange event on every check and uncheck of an item.
Delete
Using the list in mode="Delete" gives you a nice delete button and fires onDelete.
sap.m.ListType (Sample)
There's one more property you should have a look at: The type property of your items.
Every item inherits from sap.m.ListItemBase and thus has an attribute called type. Let's see how it looks like:
<items>
<ObjectListItem
type="Active"
press=".onObjectListItemPress"
detailPress=".onDetailPress"
...
/>
</items>
There are these types listed in the sap.m.ListMode documentation:
Active
Depending on the mode, the itemPress of the list and press of the list item can be fired. The selected item gets highlighted so the user can see what's selected.
Detail
A detail button (with icon sap-icon://edit) is offered which fires the detailPress event.
DetailAndActive
As the name says, this is a combination of Detail and Active type. So you have the detail button firing detailPress on button click, and the item itself firing the list event itemPress.
Navigation
The items have a navigation like look, and itemPress and item's press are called.
Inactive
No item event gets called from the item itself.
Now let's take a look at your problem. You should either assign your Table control a mode or assign your items a type. After that change the events should get fired.
Generally I would avoid using a ListMode and a ListType at the same time since there can be unexpected behavior but check it by yourself.
Add type="Active" to ColumnListItem
...
<items>
<ColumnListItem type="Active">
<cells>
<Text text="{Name}"/>
</cells>
</ColumnListItem>
</items>
...
Yang Wang: https://scn.sap.com/thread/3697995
Simple Solution using sap.m.CustomListItem
Use set the properties of the ListItem to
type="Active" press="listPress"
<List items="{/results}">
<items>
<CustomListItem type="Active" press="listPress">
<content>
<VBox>
<FlexBox direction="Row" justifyContent="SpaceBetween" alignItems="Start">
<items>
<Text text="{PernrName}" />
<Text textDirection="RTL" text="{Document Status}" class='subtext'/>
</items>
</FlexBox>
<FlexBox direction="Row" justifyContent="SpaceBetween" alignItems="End">
<items>
<Text text="{Date}" class='subtext'/>
<Text textDirection="RTL" text="{Current Processor}" class='subtext'/>
</items>
</FlexBox>
</VBox>
</content>
</CustomListItem>
Define myItemPress member function in the controller for the XML view and reference it as
itemPress = "myItemPress"
See example
Another problem in OP's code is that itemPress is used on the level of Table instead of the level of ListItemBase. This will indeed fire click events (if type="Active" is set for the ListItemBase element, as explained in other answers here). BUT: The context of the events will not allow to derive the clicked row in the list! So you get an event, but you will not be able to tell from which item it came.
Here is what needs to be changed to identify the clicked row in OP's example, using ColumnListItem as an example for ListItemBase:
Instead of...
<Table
...
itemPress="onItemPressed"
>
<items>
<!-- sap.m.ListItemBase -->
</items>
<columns>
<!-- sap.m.Column -->
</columns>
</Table>
... use this:
<Table
...
>
<items>
<ColumnListItem
type="Active"
press="onItemPressed"
>
...
</ColumnListItem>
</items>
<columns>
<!-- sap.m.Column -->
</columns>
</Table>
To derive the model path of the clicked row you can now use code like this:
onItemPressed: function (oEvt) {
var sModelPath = oEvt.getSource().getBindingContext('myModelName').getPath();
var sDiD = this.getView().getModel("myModelName").getProperty(sModelPath + "/myModelFieldName");
}
You can also add a customData node within the CustomListItem that holds row specific information and access it's key value pairs in the event handler through something like this:
var aCustomData = oEvt.getSource().getCustomData();
But again:
Both approaches will only work if onItemPressed is called on ListItemBase
/ ColumnListItem level!