Binding OData service to a dropdwon - sapui5

I am trying to bind data in a dropdown (sap.m.Select) from a service but data is not getting displayed in the dropdown. Below is my code:
Controller
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/model/json/JSONModel"
], function (Controller, JSONModel) {
"use strict";
return Controller.extend("hmel.TravelandGuestHouse.controller.CloneTravelRequest", {
onInit: function () {
this.router = sap.ui.core.UIComponent.getRouterFor(this);
//For Train Name
this.addmodel = new JSONModel();
this.getView().setModel(this.addmodel, "Model");
this.actionTemp = this.getView().byId("trainName").clone();
this.detailModel = sap.ui.getCore().getModel("detailModel");
this.getView().setModel(this.detailModel, "detailModel");
this.router.attachRoutePatternMatched(this._handleRouteMatched, this);
},
_handleRouteMatched: function(evt) {
if (evt.getParameter("name") !== "CloneTravelRequest") {
return;
}
var that = this;
that.getView().byId("trainName").bindAggregation("items", {
path: "/TravelPrpTrainDetails",
template: that.actionTemp
});
}
});
});
View
<m:Select id="trainName" selectedKey="{detailModel>/TrainName}">
<core:Item key="{ID}" text="{TrainName}"/>
</m:Select>
Data is coming in the below form and I just want to extract TrainName attribute from it:
<entry>
<id>http://________________________/TravelPrpTrainDetails(36)</id>
<category
term="WCFODataService.TravelPropTrainDetails"
scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"
/>
<link
rel="edit"
title="TravelPropTrainDetails"
href="TravelPrpTrainDetails(36)"
/>
<title />
<updated>2019-01-03T06:02:36Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:SerialNo m:type="Edm.Int32">2</d:SerialNo>
<d:ID m:type="Edm.Int32">36</d:ID>
<d:TrainName>AJMER ASR EXPRESS 19611</d:TrainName>
</m:properties>
</content>
</entry>

​Hi Swappy, the solution is pretty simple. Your item's binding should use the same model name of the parent binding. In this case, you should have:
<core:Item key="{detailModel>Value}" text="{detailModel>Value}"/>
In general, you should always use this rule when your model is not the default one (default is when the model has no name).
<ComboBox
items="{ModelName>/ListOfValues}">
<core:Item key="{ModelName>Key}" text="{ModelName>Value}"/>
</ComboBox>
If you're using the default model you should use this kind of template:
<ComboBox
items="{/ListOfValues}">
<core:Item key="{Key}" text="{Value}"/>
</ComboBox>

Related

Table grouping resets selected values when adding new item

Here we have a very basic table with an Add button and grouping activated. When I select values for the existing items and then press the button to add a new row, my selected values are getting reset, but without grouping it works fine. Am I doing something wrong or is this a bug?
sap.ui.getCore().attachInit(() => sap.ui.require([
"sap/ui/core/mvc/XMLView",
"sap/ui/model/json/JSONModel" // sample model. Can be also an ODataModel.
], async (XMLView, JSONModel) => {
"use strict";
const control = await XMLView.create({
definition: `<mvc:View xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc">
<Table items="{
path: '/tableItems',
sorter: { path : 'group', group: true }
}">
<headerToolbar>
<OverflowToolbar>
<Title text="Test Table" />
<ToolbarSpacer/>
<Button id="addButton" text="Add" type="Emphasized" />
</OverflowToolbar>
</headerToolbar>
<columns>
<Column width="20rem">
<Label text="col0"/>
</Column>
<Column width="20rem">
<Label text="col1"/>
</Column>
</columns>
<ColumnListItem vAlign="Middle">
<Text text="{text}" />
<Select forceSelection="false" width="100%" xmlns:core="sap.ui.core">
<core:Item text="test1" key="test1" />
<core:Item text="test2" key="test2" />
<core:Item text="test3" key="test3" />
<core:Item text="test4" key="test4" />
</Select>
</ColumnListItem>
</Table>
</mvc:View>`,
afterInit: function() {
this.byId("addButton").attachPress(onPressAdd, this);
function onPressAdd() {
const oModel = this.getModel();
const aItems = oModel.getProperty("/tableItems");
const newItems = aItems.concat({
group: "3",
text: "3-1",
key: "3-1",
});
oModel.setProperty("/tableItems", newItems);
}
},
models: new JSONModel({
number: 0,
tableItems: [
{
group: "1",
text: "1-1",
key: "1-1",
},
{
group: "1",
text: "1-2",
key: "1-2",
},
{
group: "2",
text: "2-1",
key: "2-1",
},
{
group: "2",
text: "2-2",
key: "2-2",
},
],
}),
});
control.placeAt("content");
}));
<script id="sap-ui-bootstrap"
src="https://openui5.hana.ondemand.com/1.82.2/resources/sap-ui-core.js"
data-sap-ui-libs="sap.ui.core,sap.m"
data-sap-ui-theme="sap_fiori_3"
data-sap-ui-compatversion="edge"
data-sap-ui-async="true"
data-sap-ui-excludejquerycompat="true"
data-sap-ui-xx-waitfortheme="init"
></script>
<body id="content" class="sapUiBody sapUiSizeCompact"></body>
Set the growing="true" to the sap.m.Table.
This enables GrowingEnablement internally which prevents rerendering the entire ListBase (Table) when the target gets invalidated. Only the necessary item will be then appended to the table.
Generally, in order to optimize the rendering behavior, it's always a good practice to..:
Enable the growing property if the table / list is editable, shrinkable, or expandable.
Add key: <propertyName with unique values> to the ListBinding info object to benefit from the Extended Change Detection if the model is a client-side model such as JSONModel. With an ODataModel, the key is automatically added by the framework.
<Table xmlns="sap.m"
growing="true"
items="{
path: 'myModel>/myCollection',
key: <propertyName>, (if 'myModel' is not an ODataModel)
sorter: ...
}"
>

Object Page with blocks

I've got this ObjectPageLayout:
request.view.xml
<ObjectPageLayout>
<headerTitle>
...
</headerTitle>
<headerContent>
...
</headerContent>
<sections>
<ObjectPageSection
mode="Collapsed">
<subSections>
<ObjectPageSubSection title="fooBlock">
<blocks>
<blockdetail:FormBlock columnLayout="auto" /> <!-- MY BLOCK -->
</blocks>
</ObjectPageSubSection>
</subSections>
</ObjectPageSection>
</sections>
</ObjectPageLayout>
FormBlockCollapsed.view.xml (MY BLOCK)
<mvc:View xmlns:f="sap.ui.layout.form" xmlns:mvc="sap.ui.core.mvc"
xmlns:core="sap.ui.core" xmlns:l="sap.ui.layout" xmlns="sap.m"
controllerName="NAMESPACE.blocks.DetailsBlockCommon">
<FlexBox>
<HBox>
<VBox>
<f:SimpleForm >
<f:content>
<CheckBox class="sapUiSmallMarginBegin sapUiSmallMarginTop" id="myCheckbox" />
</f:content>
</f:SimpleForm>
</VBox>
</HBox>
</FlexBox>
...
</mvc:View>
So far, everything is fine. My Object page looks good a the checkbox is shown.
In my Controller request.controller.js i want to validate the checkbox in FormBlockCollapsed.view.xml
validateBlockForm: function(format){
console.log( oView.byId("myCheckbox").checked() ); //oView.byId("myCheckbox") is undefined
}
But i've no access to my checkbox in the block.
Cannot read property 'checked' of undefined
Further infos
FormBlock.js
sap.ui.define(['sap/uxap/BlockBase'], function (BlockBase) {
"use strict";
var MultiViewBlock = BlockBase.extend("NAMESPACE.blocks.FormBlock", {
metadata: {
views: {
Collapsed: {
viewName: "NAMESPACE.blocks.FormBlockCollapsed",
type: "XML"
}
}
}
});
return MultiViewBlock;
}, true);
DetailBlockCommon.js
sap.ui.define([
"NAMESPACE/controller/BaseController"
], function (BaseController) {
"use strict";
return BaseController.extend("NAMESPACE.blocks.DetailsBlockCommon", {
});
});
You can access the elements in a section by having the block's id and element's id.
First we have to define an id for the block in the xml view:
<blocks>
<blockdetail:FormBlock id="formBlock" columnLayout="auto" /> <!-- MY BLOCK -->
</blocks>
Then we generate the id of the elements like the following in the view controller. The state of the art here is to add -Collapsed-- as part of the id that adds by SAPUI5 to sections elements.
var sFieldId = this.getView().createId("formBlock") +
"-Collapsed--myCheckbox";
var oCheckbox = sap.ui.getCore().byId(sFieldId);
Check if oView is defined.
you can easily get it by this.getView()

Access model defined in manifest

Using single model definition in manifest.json
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "....i18n.i18n"
}
},
"": {
"dataSource": "mainService"
}
}
i can bind to model from XML and it's work
<List items="{path: '/myOneSet'}"> ... </List>
<List items="{path: '/myTwoSet'}"> ... </List>
but i can not access to it from code
this.getView().getModel().getProperty('/myOneSet')
or
this.getView().getModel().getProperty('/myOneSet/>param')
not work. How it accessible?
If mainService is an OData service, then your model is an ODataModel. You can access data via methods described in the API, e.g.: read()
this.getView().getModel().read('/myOneSet', {
success: function(oData, response) {
// do sg. with oData
}
});
Most of its data access methods has a second parameter-object with a success function callback. This function will be called asynchronously with the data on the given path upon successful data retrieval from the datasource. Most of the ODataModel API methods works with callbacks. You can read more about callbacks here.
If you defined model in the manifest.json file then you can access it via Component. If you created your project via template then you have a BaseController.js file which is the ancestor of your other controllers and there is a function getComponentModel. So, I would suggest you to try this code in your controller:
this.getComponentModel().getProperty('/myOneSet')
Because of the property name that you try to access I assume you are using an ODataModel. Is that correct?
If that's true you have to consider a few things... ODataModel.getProperty() does not trigger requests. Instead it will return whats already available. If you want to trigger a request you should execute an ODataModel.read(). If you want to get the loaded data from the ODataModel then you should also know when the data has been loaded. This you can achieve by attaching a change event handler when you do the binding.
Instead of describing how to access the data of an ODataModel I wrote s little jsbin example for you (or see below). Just check the change event handler. There are multiple ways to access the data.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SAPUI5 single file template | nabisoft</title>
<script src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-theme="sap_bluecrystal"
data-sap-ui-libs="sap.m"
data-sap-ui-bindingSyntax="complex"
data-sap-ui-compatVersion="edge"
data-sap-ui-preload="async"></script>
<!-- use "sync" or change the code below if you have issues -->
<!-- XMLView -->
<script id="myXmlView" type="ui5/xmlview">
<mvc:View
controllerName="MyController"
xmlns="sap.m"
xmlns:core="sap.ui.core"
xmlns:mvc="sap.ui.core.mvc">
<Table
id="myTable"
growing="true"
growingThreshold="10"
growingScrollToLoad="true"
busyIndicatorDelay="0">
<headerToolbar>
<Toolbar>
<Title text="Orders of ALFKI"/>
<ToolbarSpacer/>
</Toolbar>
</headerToolbar>
<columns>
<Column>
<Text text="OrderID"/>
</Column>
<Column>
<Text text="Order Date"/>
</Column>
<Column>
<Text text="To Name"/>
</Column>
<Column>
<Text text="Ship City"/>
</Column>
</columns>
<items>
<!-- filled via bindItems() in controller -->
</items>
</Table>
</mvc:View>
</script>
<!-- XML Fragment -->
<script id="myXMLFragment" type="ui5/fragment">
<core:FragmentDefinition
xmlns="sap.m"
xmlns:core="sap.ui.core">
<ColumnListItem type="Active">
<cells>
<ObjectIdentifier title="{OrderID}"/>
<Text
text="{
path:'OrderDate',
type:'sap.ui.model.type.Date',
formatOptions: { style: 'medium', strictParsing: true}
}"/>
<Text text="{ShipName}"/>
<Text text="{ShipCity}"/>
</cells>
</ColumnListItem>
</core:FragmentDefinition>
</script>
<script>
sap.ui.getCore().attachInit(function () {
"use strict";
//### Controller ###
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/model/odata/v2/ODataModel"
], function (Controller, ODataModel) {
"use strict";
return Controller.extend("MyController", {
onInit : function () {
this.getView().setModel(
new ODataModel("https://cors-anywhere.herokuapp.com/services.odata.org/V2/Northwind/Northwind.svc/", {
json : true,
useBatch : false
})
);
var sPath = "/Customers('ALFKI')/Orders";
var oTable = this.byId("myTable");
var oTemplate = sap.ui.xmlfragment({
fragmentContent : jQuery("#myXMLFragment").html()
});
oTable.bindItems({
path : sPath,
template : oTemplate,
templateShareable : false,
sorter : null,
filters : null,
events : {
change : function (oEvent) {
var oModel, oListBnd, aContexts, i, oObj;
console.log("1. Example: ODataModel.getProperty() does not trigger a request (but here we have the data already)!");
oModel = this.getView().getModel();
console.dir( oModel.getProperty("/Orders(10643)")); //OK
console.dir( oModel.getProperty("/Orders") ); //Not OK
console.dir( oModel.getData("/") ); //DANGER: Could contain different entities!!!!!
console.log("2. Example: Accessing the Data via ListBinding");
oListBnd = oTable.getBinding("items"); // get the ListBinding
//oListBnd = oEvent.getSource(); // this works here inside the change handler
aContexts = oListBnd.getCurrentContexts(); // the the contexts
for(i=0; i<aContexts.length; i++){
oObj = aContexts[i].getObject(); // access the items/objects
console.dir( oObj );
}
}.bind(this)
}
});
}
});
});
//### THE APP: place the XMLView somewhere into DOM ###
sap.ui.xmlview({
viewContent : jQuery("#myXmlView").html()
}).placeAt("content");
});
</script>
</head>
<body class="sapUiBody">
<div id="content"></div>
</body>
</html>
Hi Just declare this is manifest
"models": {
"createMod": {
"preload": true,
"dataSource": "CreateService",
"settings": {
}
}
and Try to Access by Controller using.
var oModelCheck = that.getOwnerComponent().getModel("createMod");

Get bound values from pressed List Item in UI5 controller

I'm a beginner to SAP Fiori (UI5) and trying to retrieve a value from a table made with sap.m.Table in SAP Web IDE. But I don't succeed. Anybody hints on how to get there?
<Table id="table0" items="{/Entity1_Set}">
<ColumnListItem detailPress=".onShowHello" type="DetailAndActive">
<Text id="text5" maxLines="0" text="{Id}" />
<Text id="text6" maxLines="0" text="{field1}" />
<Text id="text7" maxLines="0" text="{field2}" />
<Text id="text8" maxLines="0" text="Euro"/>
</ColumnListItem>
<columns>
<Column id="column0">
<Label id="label0" text="Floor"/>
</Column>
</columns>
</Table>
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/m/MessageToast",
], function(Controller, MessageToast) {
"use strict";
return Controller.extend("QuickStartApplication.controller.View1", {
onShowHello: function(){
MessageToast.show("Hello World!");
},
});
});
In the "hello world"-MessageToast, I would like to display values of the fields in my table.
You can pass parameters in the function, which is called during an event.
Please see also https://sapui5.hana.ondemand.com/#docs/api/symbols/sap.m.ListItemBase.html#event:detailPress
Using these parameters, you can access the bound data.
Please see the following code on how to read the binding context of the ColumnListItem:
detailPress : function(oEventParams){
var oListItem = oEventParams.getSource();
var oBindingContext = oListItem.getBindingContext(); var sSomePropertyValue = oBindingContext.getProperty("<nameOfProperty>"); }
Using .getProperty, you can access your field values.

How to push the data in XML view into the newly created JSON model?

How to push the data in XML view into the newly created JSON model? I have created the comboBox and retrieved the data from JSON model and also created the text area when I select the item in combo box and insert data into the text area and submit a button both the data should be pushed to newly created JSON model in sapweb ide ui5
page.view.xml:
<mvc:View height="100%" controllerName="pro.controller.Page" xmlns:core="sap.ui.core" xmlns:l="sap.ui.layout" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m">
<Page title="{i18n>title}">
<content>
<l:VerticalLayout>
<ComboBox items="{ path: '/ProductCollection', sorter: { path: 'Name' } }">
<core:Item text="{Name}" /> </ComboBox>
<TextArea value="" rows="8" />
<Button type="Accept" text="Submit" press="onPress" /> </l:VerticalLayout>
</content>
</Page>
</mvc:View>
page.controller.js
sap.ui.define([
'jquery.sap.global',
'sap/ui/core/mvc/Controller',
'sap/ui/model/json/JSONModel'
], function(jQuery, Controller, JSONModel) {
"use strict";
var PageController = Controller.extend("pro.controller.Page", {
onInit: function() {
// set explored app's demo model on this sample
var oModel = new JSONModel(jQuery.sap.getModulePath("pro", "/model/model.json"));
this.getView().setModel(oModel);
}
});
return PageController;
});
add a 'key' attribute to the combobox item. Also give the combobox and teaxarea some IDs.
<ComboBox id="selectBox" items="{ path: '/ProductCollection', sorter: { path: 'Name' } }">
<core:Item key="{Naame}" text="{Name}" /> </ComboBox>
<TextArea id="textArea" value="" rows="8" />
On click of submit, get the selected values from the combobox and text area and push them into the model. I assume that you wanted to push this new data to the existing model and also your existing model is an array of objects.
sap.ui.define([
'jquery.sap.global',
'sap/ui/core/mvc/Controller',
'sap/ui/model/json/JSONModel'
],function(jQuery, Controller, JSONModel) {
"use strict";
var PageController = Controller.extend("pro.controller.Page", {
onInit: function() {
var oModel = new JSONModel(jQuery.sap.getModulePath("pro", "/model/model.json"));
this.getView().setModel(oModel);
},
onPress: function() {
//get the value of the selected item in the combobox
var selectedVal = this.getView().byId("selectBox").getSelectedKey();
//get the textarea value
var textAreaVal = this.getView().byId("textArea").getValue();
this.getView().getModel().oData.push({
key: selectedVal,
value: textAreaVal
});
}
});
return PageController;
});