How to convert OData model to entityset in sap ui5 - javascript

I want to use smart Table like in this sapui5 explored sample but the problem is I have a OData model and the example shows only how we can handle the binding with mock data and also I didn't understand the metadata.xml file. I guess oData model has also its own metadata document. Here my codes in controller :
this.DataPath = "QuarterPerformanceSet";
var oModel = new sap.ui.model.odata.ODataModel(model.Config.getServiceUrl(), true, model.user, password);
oModel.setCountSupported(false);
oSmartTable.setModel(oModel);
oSmartTable.setEntitySet(this.DataPath);
but it doesn't work. I got this error :
Component-changes.json could not be loaded from ./Component-changes.json. Check for 'file not found' or parse errors. Reason: Not Found -
getChanges' failed: -
Simply how can I set entitySet using my odata model?
my view:
<smartTable:SmartTable id="idSmartTable" tableType="Table"
useExportToExcel="true" useVariantManagement="false"
useTablePersonalisation="true" header="Line Items" showRowCount="true"
persistencyKey="SmartTableAnalytical_Explored" enableAutoBinding="true"/>
Thank you in advance if someone can help.
UPDATE 2 : I rebind table according to this discussion
this.DataPath = "QuarterPerformanceSet";
var oModel = new sap.ui.model.odata.ODataModel(model.Config.getServiceUrl(), true, model.user, password);
oModel.setCountSupported(false);
var oSmartTable = this.getView().byId("idSmartTable");
oSmartTable.setModel(oModel);
oSmartTable.setEntitySet(this.DataPath);
oSmartTable.rebindTable();
sad to say but still I got same error.

You need to pass the name of entity set, not the model instance. If you have for example an entity set Customers defined you just do:
oSmartTable.setEntitySet("Customers");
or add the attribute entitySet to your table declaration.
<smartTable:SmartTable id="idSmartTable" entitySet="ENTITY_SET" .../>

Related

xml view binding data from two entitysets

I am working on a Master-Detail app. I have a view with list control and I am binding the same with the data from an entityset called "entityset1".
Odata -> data from the entityset1
<serialno>122333</serialno>
I do have another entityset called entityset2 in the same service.
Odata -> data from the entityset2
<hdata>is Active</hdata>
Data from above entityset2 will only be retrieved with the filter (/sap/opu/odata/sap/My_SRV/entityset2?$filter=(serialno=122333)
I am now trying to retrieve the value from the entityset2 and trying to bind it to one attribute in my list. This list is already binded with the entityset1 data.
Myview.xml.
<List id="list" select="_handleSelect">
<ObjectListItem id="MAIN_LIST_ITEM" press="_handleItemPress" title="{Name}">
<attributes>
<ObjectAttribute id="ATTR1" text="{serialno}" />
<ObjectAttribute id="ATTR2" text="{entityset2/hdata}" />
</attributes>
</ObjectListItem>
</List>
Controller.js (binding using the below lines)
this.oList.bindAggregation("items", {
path: '/entityset1',
template: this.oListItem,
filters: this.searchFilters
});
var oserialnum = this.getView().getBindingContext().getObject().serialno;
var oHdata = new sap.ui.model.Filter("serialno", "EQ",oserialnum);
this.searchFilters = new sap.ui.model.Filter([oserialnum],true);
this.oList.bindAggregation("items",{
path : "/entityset2",
filters :this.searchFilters
});
However I am getting an error "Cannot read property 'getObject' of undefined" on this line "this.getView().getBindingContext().getObject().serialno".
Can someone kindly advise how to retrive the data from the entity2 and binding it to the list, ?
You cannot get BindingContext using the view. Read more about binding Context - it's a pointer to an object in Model data.
Also, serialNo(the parameter you are trying to retrieve from the Model is also contextual i.e. it differs with each row item).
One way to do this would be:
onListeItemPress Event of the List
<ObjectListItem ... ... press="onListItemPress" >
In the corresponding Controller
`onListItemPress : function(oEvent){
var oserialnum = Event.getSource().getBindingContext("mainODataModel")..getProperty("serialNo")`
Let me know if this helps.
If I understand you correctly what you need is associations.
They will allow the OData Service to deliver the needed Data from entityset2 directly with the entityset1 through "associating" entityset2 with your serial number.
If you are using a SAP Backend and SEGW this Blog might help you:
https://blogs.sap.com/2014/09/24/lets-code-associationnavigation-and-data-provider-expand-in-odata-service/
I was faced with a similar issue whilst creating a Master-Detail App, but found out from the SAP Forums that this is not possible, which makes sense and ended up creating a separate entityset in the Backend having a link to the other set

How to copy data from OData v4 to JSON with SAP UI5?

I'm using OData v4 to load data from my backend to my frontend (developed with SAP UI5) and I am using a form to display a detail page. When I click the "edit" button I'm able to edit the data. My implementation is similar to this example: https://sapui5.hana.ondemand.com/explored.html#/sample/sap.ui.layout.sample.Form354/code/Page.controller.js
When editing something, the data is directly edited at the model and, therefore, updated at the backend. However, I want to be able to choose if I want to save the changes or if I want to cancel the edit before it is updated at the backend.
I read on other questions that one can copy the ODataModel to a JSONModel and use that copy instead, by doing something like:
var oModel = this.getView().getModel();
var oModelJson = new sap.ui.model.json.JSONModel();
oModel.read("/Data", {
success: function(oData, response) {
oModelJson.setData(oData);
sap.ui.getCore().setModel(oModelJson, "oJSONModel");
alert("Success!");
},
error: function(response) {
alert("Error");
}
});
However, the read method seems not to be available for OData v4. the code of my controller where the data is loaded looks like following:
onInit: function() {
this.oModel = new ODataModel({
groupId : "$direct",
synchronizationMode : "None",
serviceUrl : '/odata/'
});
this.getView().setModel(this.oModel, 'oModel');
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.getRoute("details").attachPatternMatched(this._onObjectMatched, this);
this._showFormFragment("display");
},
_onObjectMatched: function (oEvent) {
this.getView().bindElement({
path: "/Data(" + oEvent.getParameter("arguments").dataPath + ")",
model: "oModel"
});
//I want to copy the data from the ODataModel to the JSONModel here
},
What's the best way to accomplish this? And how to do it with OData v4?
I suppose you want to resetChanges in case user cancels the save.
For V2 ODataModel, there is deferedGroup concept which you can use to resetChanges or submitChanges.
I have not much experience with V4. Though from the documentation, it is possible.
Please try to pass a updateGroupId in the constructor. Then you can choose resetChanges or submitBatch by group Id.
mParameters.updateGroupId? The group ID that is used for update requests. If no update group ID is specified, mParameters.groupId is used. Valid update group IDs are undefined, '$auto', '$direct' or an application group ID, which is a non-empty string consisting of alphanumeric characters from the basic Latin alphabet, including the underscore.
Thank you!

How to bind the odata services to SAPUI5 table?

I've used the below code to bind the odata services to sapui5 table
I was not able to get the data from the oData service to the SAPui5 table, odata is stored in separate vpn client. I'm using reverse proxy server to retrieve the data
Error in the console is shown in the below link
Code:
//Creating the instance of oData model
var oModel = new sap.ui.model.odata.v2.ODataModel("http://admin-think:88/sap/...",{useBatch : true});
sap.ui.getCore().setModel(oModel,"model1");
console.log(oModel);
// Create instance of table
var oTable = new sap.ui.table.Table({
visibleRowCount : 6,
selectionMode: sap.ui.table.SelectionMode.Single,
navigationMode: sap.ui.table.NavigationMode.scrollbar,
selectionBehavior: sap.ui.table.SelectionBehavior.RowOnly
});
// First column "Application"
oTable.addColumn(new sap.ui.table.Column({
label : new sap.ui.commons.Label({
text : "APPLICATION",
textAlign : "Center",
}),
template : new sap.ui.commons.TextView({
textAlign:"Center"}).bindProperty("text","model1>Applno"),
}));
// Bind model to table control
oTable.bindRows("model1>/");
Your service end-point is probably incorrect in this line: var oModel = new sap.ui.model.odata.v2.ODataModel("http://admin- think:88/sap/...",{useBatch : true});.
In the error output you sent, you can see that the application is trying to reach URL http://.../ZTEST1_SRV/CoreOpenAppSet()/$metadata. This results in a 404 status, meaning that that service is not available on that URL. The right URL for the app to download metadata from should probably be http://.../ZTEST1_SRV/$metadata instead.
To solve this, you should remove the CoreOpenAppSet() portion of the variable you're passing to the ODataModel constructor. Instead you should call this 'Function Import' using the callFunction of your ODataModel, i.e.: oModel.callFunction().
When the call of the function import completes and the returned promise is resolved, you can bind the result of the call to your UI using setBindingContext:
var oPromise = oModel.callFunction("/CoreOpenAppSet");
oPromise.contextCreated().then(function(oContext) {
oView.setBindingContext(oContext);
});
Also, it's a good practice to specify your model and endpoints in the manifest so that they're separated from your code. You can learn more about that here: https://sapui5.netweaver.ondemand.com/docs/guide/8f93bf2b2b13402e9f035128ce8b495f.html

Using read function of oData model in UI5

I am coding an UI5 App which consumes a given OData Service. Now I want to get the name of an account with a given account number and Display it in a table. As I can only access the account Name via /AccountInfoSet()/ShortText I tried to use a formatter function to map the account number.
Binding in View:
Formatter function in Controller:
numToNameFormatter : function(sNum){
var text = this.getView().getModel().read("/AccountInfoSet('" + sNum + "')", null, null, true,
function(oData, oResponse){
return JSON.stringify(oData);
},
function(){
alert("Read failed");
});
return text;
}
This should return the requested object as a string. The data is requested successfully, as I verified via an alert. The problem is, that I can't get the data out of the call back, as it ist asynchronous. How do I get the data.
Thanks in advance!
Not sure if your data model is set up like this, but would it be possible to expand your table set to also load the related AccountInfoSet's?
I mean, if your table holds for instance an array of Accounts, and each Account entry has a related AccountInfo, you could just fill your table with the following:
http://your.service/Accounts/?$expand=AccountInfo
You then bind the field in your table directly, without a formatter:
<TextField value="{AccountInfo/0/ShortText}">

SAPUI5 Create OData entity with dates - generates incorrect request payload that ends in CX_SXML_PARSE_ERROR

We are trying to create an entity that has date attributes via an odata service. Backend is an sap system. This entity has only 3 key attributes plus a bunch of other attributes. We have identified that dates in the keys are the root cause of the problem.
Keys:
Pernr type string,
begda type datetime
endda type datetime.
The code below, (which does not work), has been severely simplified when trying to troubleshoot the issue. At the moment, it reads an entity from an entity set and immediately tries to create one with exactly the same data.
Code:
var oODataModel = new sap.ui.model.odata.ODataModel("/sap/opu/odata/sap/Z_PERSONAL_DATA_SRV/");
//Test entity to be saved
var entity = null;
//Handler for read error
var handleReadE = function (oEvent){
alert("error");
};
//Handler for read success
var handleRead = function (oEvent){
//Get the data read from backend
entity = oEvent.results[0];
//Try to create a new entity with same data
oODataModel.create('/PersDataSet', entity, null, function(){
alert("Create successful");
},function(oError){
alert("Create failed", oError);
});
};
oODataModel.read("/PersDataSet", null, [], true, handleRead, handleReadE);
In the gateway error log, an xml parsing error appears. In this log, we can see the request data and it can be seen that the dates are transported with String types. These dates are defined in the service as DateTimes so the request is rejected.
Example:
<m:properties>
<d:Pernr m:type="Edm.String">00000001</d:Pernr>
<d:Endda m:type="Edm.String">9999-12-31T00:00:00</d:Endda>
<d:Begda m:type="Edm.String">1979-05-23T00:00:00</d:Begda>
When the entity is read, the backend does not send any type information. It sends like the following example:
<m:properties>
<d:Pernr>72010459</d:Pernr>
<d:Endda>9999-12-31T00:00:00</d:Endda>
<d:Begda>1876-07-21T00:00:00</d:Begda>
And, indeed, if we try to save the same info without the type=".." it works. So the problem are the incorrect types ODataModel.create adds to the xml.
My question is:
Can I tell ODataModel.create to not add this type info? It is not doing a good job inferring the types.
Can anyone share an example reading and writing dates through odata?
Thank you very much in advance.
the data returned from oODataModel.read is raw, before you post you need to parse it
var handleRead = function (oEvent){
//Get the data read from backend
entity = oEvent.results[0];
var newEntity = jQuery.extend({},entity);
delete newEntity.__metadata;
newEntity.Begda = new Date(entity.Begda);
newEntity.Endda = new Date(entity.Endda);
//Try to create a new entity with same data
oODataModel.create('/PersDataSet', newEntity, null, function(){
why not use json instead of xml?
Thanks all for the help.
We got this working accounting for the following:
The problem of the wrong types appended to the attributes comes from the read itself. The object returned by read has a __metadata attribute which describes the values. In this object the dates are set with type=edm.string, even when the service says they are DateTime. To me this is a bug of the .read function.
When trying to use the same object to save, create sees the __metatada on the entry and uses those values, producing type edm.string type for the dates. This caused the request to be rejected. Manually changing these __metadata.properties...type to Edm.DateTime makes it work.
In the end, we did the following:
Dates are parsed manually from the Odata response, creating a js Date
object from the strings in format "yyyy-mm-ddT00:00:00", to make it work with control bindings. When we want to save, the reverse is done.
The object to be created is a new object with
only the attributes we care (no __metadata)

Categories

Resources