How to set/get selected text in sap.m.select? - sapui5

I only find setSelectedItem setSelectedItemId setSelectedKey in sap.m.select doc, how to setSelected text in sap.m.select?
For example:
<Select
forceSelection="false"
selectedKey="{/ProductCollection/0/ProductId}"
items="{
path: '/ProductCollection',
sorter: { path: 'Name' }
}">
<core:Item key="{ProductId}" text="{Name}" />
</Select>`
How to get selected text (Name) in this control ?

The keys shall be unique but the texts do not have to be unique. In some situations the texts are translated but the keys stay the same. Thats why the keys are used for selection.
To get the text of the selected item you can use
var text = select.getSelectedItem().getText();
To select an item by text you have to search the model for the item, get its key and use that with setSelectedKey().

Related

List control breaks after grouping aggregation

I have two problems with a sap.m.List. I'm trying to group values by a given date.
The grouping shows duplicates group headers, despite having the same values.
The actual list items are not showing at all.
I'm binding everything in the controller. When I remove the sorter, the list behaves correctly and shows all data correctly. But as soon as I add the grouping, the list breaks.
XML View (the item is more complex, for simplicity all other variables have been removed):
<List id="idListCart" noDataText="{i18n>CartListNoData}">
<CustomListItem id="listItemTemplate">
<layout:Grid class="sapUiSmallMarginTop" hSpacing="1">
<VBox alignItems="Start" class="sapUiSmallMarginEnd">
<Text text="{Fullname}" />
<Text text="{Startdatum}" />
</VBox>
</layout:Grid>
</CustomListItem>
</List>
Controller:
this.byId("idListCart").bindItems({
path: "/CartSet",
template: this.byId("listItemTemplate"),
filters: aFilters,
sorter: new Sorter({ // required from "sap/ui/model/Sorter"
path: "Startdatum",
group: function(oContext) {
return /* formatted date */;
}
}),
groupHeaderFactory: function(oGroup) {
return new GroupHeaderListItem({ // required from "sap/m/GroupHeaderListItem"
title: oGroup.key
});
},
});
Any ideas what I am doing wrong?
Generally, it's not a good practice to declare a template in XML without predefining the corresponding list binding in the parent control. Otherwise, it's just adding a plain single item which UI5 renders together with the List initially. That single item gets then cloned and replaced in the 2nd rendering cycle after the list binding from the controller is complete. I guess this is where the grouping has issues; the first item is no longer sap.m.CustomListItem but sap.m.GroupHeaderListItem causing side effects when rendering the rest of the items.
Better create the template in the controller entirely:
<List id="idListCart" noDataText="{i18n>CartListNoData}">
<!-- Template control is created in the controller. Nothing to define here. -->
</List>
{ // Items binding info
path: "/CartSet",
templateShareable: false,
template: new CustomListItem({ // required from "sap/m/CustomListItem"
// ...
}),
// ...
}
This does add quite a few more LOC to the controller but avoids unexpected side effects.
We could keep the template definition in XML by wrapping it with <dependents> but that practice caused other issues in my experience with some outdated SAPUI5 controls. But you might want to give it a try:
<List id="idListCart" noDataText="{i18n>CartListNoData}">
<dependents> <!-- Controls that belong to parent but aren't supposed to be rendered -->
<CustomListItem id="listItemTemplate">
<!-- ... -->
</CustomListItem>
</dependents>
</List><!-- No change in the controller -->
Alternative
If possible, define the list binding directly in XML where Sorter can be created declaratively, with its grouper and group header factory assigned using the '.<fnName>' syntax. Dynamic filters would still need to be created and added to the list binding separately in the controller.
<List id="idListCart"
noDataText="{i18n>CartListNoData}"
items="{
path: '/CartSet',
sorter: {
path: 'Startdatum',
descending: true,
group: '.formatDate'
},
groupHeaderFactory: '.createGroupHeader',
suspended: true
}"
><!-- Template as usual: -->
<CustomListItem>
<!-- ... -->
</CustomListItem>
</List>
The list binding is suspended first in order to prevent sending a request prematurely without the $filter query. Once the binding resumes, a single request will be sent instead of two.
{ // Controller
onInit: async function() {
const myFilters = new Filter({/* ... */}); // required from "sap/ui/model/Filter"
await this.getOwnerComponent().getModel().metadataLoaded(); // preventing race condition
this.byId("idListCart").getBinding("items") // access ODataListBinding
.filter(myFilters, "Application")
.resume(); // starts sending the request from here.
},
formatDate: function(oContext) {
return /* formatted date */;
},
createGroupHeader: function(oGroup) {
return new GroupHeaderListItem({ // required from "sap/m/GroupHeaderListItem"
title: /* formatted group header using oGroup.key */
});
},
// No list binding from controller
}

SAPUI5 How to display only the first element of an expanded entitySet in table

I am currently using an entityset(i.e, "SolutioningVersions") in my smarttable which i have expanded in controler using
var mBindingParams = oEvent.getParameter("bindingParams");
mBindingParams.parameters["expand"] = "TEAMID/TEAMDETAILS,SOLREQ,SOLESTIMATE";
I have bound it in my table using
<VBox items="{ path: 'SOLESTIMATE', templateShareable:false }">
<Text text="{WBSVARIANT}"/>
</VBox>
But "SOLESTIMATE" is having array of objects & i want to show only "WBSVARIANT" from it 1st object in array.
Currently it shows me like this in single cell of table
enter image description here
I want to show only 1st element of this array. Also, i dont want to filter array here as objects are not unique.
A formatter can help you:
<Text text="{path: 'WBSVARIANT', formatter: '.formatText'}"/>
function formatText(items){
return items[0];
}

ComboBox in UI5 does not display ValueState

ComboBox is not showing state like Error, Warning with highlight around the borders. But it does change the state. For example, if it is error state, and if I try to enter new value in combobox, it will show that "invalid Entry" tip near the box. But the box borders are never highlighted in red. Below is the code:
XML.view
<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:l="sap.ui.layout">
<Dialog id......>
<ComboBox id="combo1" change="cChanged" items="{path: '/results'}">
<items>
<core:Item key="{ID}" text="{Name}"/>
</items>
</ComboBox>
</Dialog>
Controller.js
cChanged: function(oEvent) {
var newval = oEvent.getParameter("newValue");
var key = oEvent.getSource().getSelectedItem();
if (newval !== "" && key === null) {
sap.ui.getCore().byId("combo1").setValueState("Error");
oEvent.getSource().setValue("");
sap.m.MessageToast.show("Please select from existing IDs")
flag = false;
} else {
oEvent.getSource().setValueState('None');
}
You can also access combo1 control instance by using oEvent.getSource() event OR use byId() from the sap.ui.core.Fragment class and not sap.ui.getCore().byId()
Also, if you are writing a logic only to validate if what the user input in the combobox is a valid item, consider replacing your ComboBox by the sap.m.Select control.
Both ComboBox and Select has same look and feel, but Select does not allow a manual input. It can also have an empty option if you use the property forceSelection

Conditional column value in UI5 table

I have a column in table whose value is bound to a property of data model.
text = { modelName>/OrderNo}. How to make it conditional based on a flag? If property from Model isReturnable = true, I want to show text = {modelName>/ReturnNo} else I want to show {OrderNo}. How to built syntax for that?
<table:Column>
<Label class="smartist-table-column-header" text="Qty Returned"/>
<table:template>
<Text text="{ path: 'OrderDetail>OrderNo'}"/>
</table:template>
</table:Column>
You can use expression binding.
See URL for details: https://ui5.sap.com/#/topic/daf6852a04b44d118963968a1239d2c0
Solution to your problem:
<Text text="{= ${modelName>isReturnable} ? ${modelName>/ReturnNo} : ${OrderDetail>OrderNo}}" />
As expression binding would be a more appropriate approach to this problem,
Custom formatting can also be one way to achieve this.
In the view:
<Text text= "{ parts:[
{path: "modelName>isReturnable"},
{path: "modelName>ReturnNo"},
{path: "modelName>OrderNo"},
],
formatter: '.formatOrderNo'
}"/>
In the corresponding controller
formatter: function(isReturnable, sReturnNo, sOrderNo){
if(isReturnable == true){
return sReturnNo;
}else{
return OrderNo;
}
}
In case of more complex logic where you need to perform some calculations/manipulations on the fields before binding, custom formatting is the way to go. Custom Formatters in SAPUI5

Get value from checkbox in SapUI5

I have a main.controller.js where I want to check the value of a Checkbox. If the checkbox has been checked, the first flexbox will be shown and the second flexbox will not be shown in the fragment.
This my controller.js:
checkDone: function () {
var checkV = this.byId("ch1").getSelected();// not working
}
This my fragment.xml
<CheckBox id="ch1" select ="checkDone" text="Check"></CheckBox>
<FlexBox class="sapUiSmallMarginEnd" id="f1">
<Input value=""></Input>
</FlexBox>
<FlexBox direction="Column" id="f2">
<Input value=""></Input>
</FlexBox>
This code works (see example with sap.m.Checkbox here).
Just a recommendation: in your checkbox's 'select' handler you use:
this.byId("ch1").getSelected();
in order to whether the checkbox is selected or not, but this value is already given as a parameter of the select handler:
checkDone: function (oEvent) {
var bSelected = oEvent.getParameter('selected'));
}
Simmilar is for the sap.ui.commons.Checkbox API. Check change event.
It looks like the View.byId function returns an element in its initial form. When you find element from DOM, getSelected() function works as expected.
Instead of getSelected() try getChecked().
getChecked() will return true or false based on checked/unchecked.