Binding OData Property in SAPUI5 List - odata

I created an EntityType in my gateway project. How can I bind that value to a list in SAPUI5?
<List id="id1" mode="{path: 'ODataManifestModel>EntitySetForBoolean', formatter: 'Formatter.formatForBoolean'}""
items="{..}"
so I define in my manifest JSON the gateway service and call it ODataManifestModel. Now I'd like to bind that value from the booleanProperty and depending on that value change the mode of my list. All that is clear to me how to do but somehow I think I am not binding it correctly. Because with that I am not sure how the frontend will know that I was to use that specific property. I also tried something like this:
<List id="id1" mode="{path: 'ODataManifestModel>EntitySetForBoolean>booleanProperty', formatter: 'Formatter.formatForBoolean'}""
items="{..}"
but that didn't work either, what I am doing wrong here?

'ODataManifestModel>EntitySetForBoolean>booleanProperty'
A few things:
your screenshot is probably wrong because you always need the entitySet name that can be found in the "folder" Entity Sets not the Entity Type. Although your name looks correct.
you have to bind one element of the entitySet (array) to the mode property specifying it with its defined key in SEGW -> your entitytype needs at least one key field. You cannot acces oData entitSet elements in an OdataModel with an index
you need an absolute path if you are referencing the entitySet, means after model> it must start with /. Alternatively in your controller init method after metadata loaded, bind one element to the whole view
var that = this;
this.getOwnerComponent().getModel().metadataLoaded().then(function() {
that.getView().bindElement({path:"/EntitySetForBoolean('1234')" });
}) to use relative binding in the view (not starting with /)
the path within the structure uses / instead of >
Absolute Binding:
"ODataManifestModel>/EntitySetForBoolean('1234')/booleanProperty"
Or if the element is bound to the view or a parent container object in the view, you can use a relative path:
"ODataManifestModel>booleanProperty"

mode property from ListBase can have a the following properties (None, SingleSelect, MultiSelect, Delete) and it is applied to all the list elements

Am assuming your service looks similar to this via URL, there is no sample data provided in your question: Northwinds oData V2.
Open preview in external window
Here am using the Products Entity set.
//manifest.json
"dataSources": {
"ODataManifestModel": {
"uri": "path_to_your_service",
"type": "OData",
"settings": {
"odataVersion": "2.0",
"localUri": "",
"annotations": []
}
},
..."models": {
"ODataManifestModel": {
"type": "sap.ui.model.odata.v2.ODataModel",
"dataSource": "ODataManifestModel"
},
..
}
//view.xml
<mvc:View controllerName="sap.otuniyi.sample.Master" xmlns:mvc="sap.ui.core.mvc" xmlns:core="sap.ui.core" xmlns="sap.m" xmlns:semantic="sap.m.semantic">
<semantic:MasterPage id="page" title="Contents">
<semantic:content>
<List items="{ODataManifestModel>/Products}" mode="SingleSelectMaster" noDataText="No Data Available" growing="true" growingScrollToLoad="true" selectionChange="onSelectionChange">
<items>
<ObjectListItem title="{ODataManifestModel>ProductName}" type="Active" icon="sap-icon://user-settings" press="onSelectionChange" />
</items>
</List>
</semantic:content>
</semantic:MasterPage>
</mvc:View>

Related

Elasticsearch repository not allowing default field type

While creating an index Elasticsearch Repository does not allow default type. If field type annotation is missing, assuming default type, the Spring data elasticsearch mapper throws exception and then creates some default mapping when I save the first object.
I'm wondering if it is somehow possible to not annotate every field in of my data objects?
I'm using Spring Data Elasticsearch v3.1.8 and Elasticsearch 6.2.2.
Thanks
There is effectively a way to avoid annoting every fields. Elasticsearch need to create the mapping of the document.
You can indicate to spring how the document need to be mapped with #Field or by providing the mapping configuration.
With spring just annotate the document with #Mapping to set mapping file location.
Also you could just create the mapping using Elasticsearch PUT mapping API.
#Document(indexName = Produit.INDEX, type = ProduitES.TYPE, shards = 1)
#Mapping(mappingPath = "/mappings/mappings-produit.json")
public class Produit {
private String code;
private String name;
...
}
The mapping file in resources/mappings/mappings-produit.json folder :
{
"produit": {
"dynamic": "strict",
"properties": {
"code": {
"type": "text",
},
"name": {
"type": "text",
"index": false
}
}
}
}

Multiple $expand Parameters in OData binding

I have a table binding and consuming the publicly available OData service from the ES4 SAP system. My root entity set is ProductSet and it has 2 navigation properties: ToSupplier and ToSalesOrderLineItems.
I am able to issue the $expand parameter in the table bindings as follows, but could you please assist me in how I can pass both navigational properties so that the OData service expands both ToSupplier + ToSalesOrderLineItems?
<Table items="{
path: '/ProductSet',
parameters: {
expand: 'ToSupplier'
}
}">
expand: "ToSupplier,ToSalesOrderLineItems"
If "ToSupplier" was a parent of "ToSalesOrderLineItems" then it would look like this:
expand: "ToSupplier/ToSalesOrderLineItems"

Binding OData sub collection not working

Given the following data source (OData V2):
Types: Customer, Project, Customer have a collection of Projects
So /Customer is providing me a List of Customers,
Alike /Project
and /Customer(guid'xxxx')/Project is providing me a list of projects associated with the customer.
Now, given a View (List) on /Customer is showing me the customers. Having the routing set up so that selecting the individual Customer moves to a separate CustomerDetail View which shows details of the customer as well as its Project collection. Details of customer are shown perfect, I also get one row per Project, however, Project fields like name, description etc. are not shown in the list. Investigating further, clicking on a list item and thus invoking the event handler shows me that the list items have as BindingPath /[object Object] which is not what I expect.
Binding the List on /Project is working perfectly but shows all projects, not only those of the Customer.
To make things more complicated, when I add a new Project through a Dialog to the List (thereby doing a Create on the OData Model), I can see that there is a roundtrip to the server and the OPENUI5 is requerying the projects (using ' /Customer(guid'xxxx')/Projectinstead of the initial query with/Customer(guid'xxxx')?$expand=Project`. Then, the list is fully populated! Please note that all the time, there is no change in my binding, this is purely internal magic by OPENUI5.
The odata source provides as follows:
{
"d" : {
"__metadata" : {
"id" : "http://BASEADDR/Data.svc/Customer(guid'XXX')",
"uri" : "http://BASEADDR/Data.svc/Customer(guid'XXX')",
"type" : "CNTM.Customer"
},
"Project" : [{
"__metadata" : {
"id" : "http://BASEADDR/Data.svc/Project(guid'XXX')",
"uri" : "http://BASEADDR/Data.svc/Project(guid'XXX')",
"type" : "CNTM.Project"
},
"Id" : "XXX",
"CustomerId" : "XXX",
"Name" : "Noch eins",
"Description" : "",
"IsDeleted" : false
}, ...
],
"Id" : "XXX",
"Name" : "TEST",
"IsDeleted" : false
}
}
Customer includes Project Collection with multiple projects.
Binding on XML View is:
<Table items="{Project}">
The event handler on the item is:
onProjectItemPress: function (oEvent) {
var oItem = oEvent.getSource();
var oCtx = oItem.getBindingContext();
var gId = oCtx.getProperty("Id");
this.getRouter().navTo("project", {
projectId: gId
});
}
and the result in the console is
oCtx : constructor {oModel: constructor, sPath: "/[object Object]"}
I have been using this kind of binding approach already in other projects, but this rather trivial sample is really strange...any ideas?
Thanks, regards
Jörg Fischer

Custom DataService adapter saveChanges method to set entities to Unchanged

I've implemented a custom DataService adapter for BreezeJS - I wanted to use Breeze with a RESTful back end service (not OData or ASP.NET Web API).
So far - decent results after a learning curve.
I'm having an issue that when I call save changes - afterwards my entities on the client do not get marked as 'Unchanged'. They keep the same entityState.
I assume it has something to do with the success handler of the AJAX request to the backend service (looking at the source code to the WebAPI adapter):
success: function(data, textStatus, XHR) {
if (data.Error) {
// anticipatable errors on server - concurrency...
var err = createError(XHR);
err.message = data.Error;
deferred.reject(err);
} else {
// HACK: need to change the 'case' of properties in the saveResult
// but KeyMapping properties internally are still ucase. ugh...
var keyMappings = data.KeyMappings.map(function(km) {
var entityTypeName = MetadataStore.normalizeTypeName(km.EntityTypeName);
return { entityTypeName: entityTypeName, tempValue: km.TempValue, realValue: km.RealValue };
});
var saveResult = { entities: data.Entities, keyMappings: keyMappings, XHR: data.XHR };
deferred.resolve(saveResult);
}
},
It looks like the response includes an array of 'Entities'. What do these 'Entities' look like? It echoes what the client sent with an updated entityAspect.entityState value (server responses with 'Unchanged')?
Is that what should be passed into the deferred.resolve call?
I've got a working solution for this.
In a nutshell here's what is required for the object that is passed to the
deferred.resolve(saveResult);
Call in the success handler of the save change AJAX request.
Server response should include information about how to map from the client generated id to the server generated id (if the server generated one). This can be one keyMapping property returned in the response (like the Breeze API controller does) or what my service does is return a keyMapping property as a child property of a particular resource
The client code should create an array of objects that look like:
{ entityTypeName: "fully qualified entity type name",
tempValue: "client generated id",
realValue: "server generated id"
}
this array is the keyMappings property of the saveResult object
the entities property of the saveResult object is a flat list of all the entities that were modified from the server. Because of the design of my service API, it can return an entity, and child entities embedded in it, which I had to traverse and pull out into a flat list. Additionally these entity objects should be 'raw' and not include the entityAspect property or anything Breeze might interpret as a 'real' entity.
Also - something that can also be helpful is to look at the new sample from the Breeze folks - the MongoDB Breeze sample. They've implemented a custom dataServiceAdapter that hooks up their NodeJS/MongoDB backend. That provided some additional insight as well.
Good luck!

Viewing Odata response in web browser

Hi All I have used Odata4j to create Odata Service and deployed in tomcat. When i use Sesame Data Browser i can see a Table (if i click on THREAD ) having header.
My question what should be the url to see the same data in web-browser? I want to consume this in a service so want to know url.
If i type this in http://localhost:8888/OdataEx/example.svc browser i can see some XML
<?xml version="1.0" encoding="utf-8" ?>
<service xmlns="http://www.w3.org/2007/app" xml:base="http://localhost:8888/OdataEx/example.svc/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app">
<workspace>
<atom:title>Default</atom:title>
<collection href="Threads">
<atom:title>Threads</atom:title>
</collection>
</workspace>
</service>
and Java code generating service is
public class ExampleProducerFactory implements ODataProducerFactory {
public ODataProducer create(Properties properties) {
InMemoryProducer producer = new InMemoryProducer("example");
// expose this jvm's thread information (Thread instances) as an entity-set called "Threads"
producer.register(Thread.class, Long.class, "Threads", new Func<Iterable<Thread>>() {
public Iterable<Thread> apply() {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
while (tg.getParent() != null)
tg = tg.getParent();
Thread[] threads = new Thread[50];
int count = tg.enumerate(threads, true);
return Enumerable.create(threads).take(count);
}
}, Funcs.method(Thread.class, Long.class, "getId"));
return producer;
}
}
To see a specific entity set just append the entity set name to the URL. For example:
The sample service URL is: http://services.odata.org/OData/OData.svc/
To see the Products entity set, go to: http://services.odata.org/OData/OData.svc/Products
Note that this is also described in the service document returned by the .svc directly. Each collection element has an href attribute which is a relative URL pointing to that collection.
If you want to see data from browser then just add entityset name after .svc. you can also put the query to see the filterd data
The sample service URL is: http://services.odata.org/OData/OData.svc/
http://services.odata.org/OData/OData.svc/entitynameset

Resources