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
Related
I have an API to retrive all products with Paging and Sorting functions as follow:
#ApiImplicitParams({
#ApiImplicitParam(name = "page", dataType = "integer", paramType = "query", value = "The page number that should be returned. Default is 0."),
#ApiImplicitParam(name = "size", dataType = "integer", paramType = "query", value = "How many items the page should have. Default is 20."),
#ApiImplicitParam(name = "sort", allowMultiple = true, dataType = "string", paramType = "query", value = "Sorting order, e.g. asc or desc. Default is asc")})
public ResponseEntity<Product[]> getAllProducts(Pageable pageable) {}
And then I use Codegen to generate Client API but the problem here is the method's signature that it generated is not the one that I am expecting:
public List<Product> getAllProductsUsingGET(Object page, Object size, List<String> sort){}
What I would like to have here is getAllProductsUsingGET(Pageable pageable)
Did I make some mistake with the configuration? Can anyone give me some hint how to achieve only pageable as parameter instead of each single property like that? Thank you very much!
you are defining the API implicit parameters to include exactly those 3 parameters. Nonetheless, I don't think the final API should contain signatures that include Pageable params as these are dependency of Spring and you don't want your "connector" API to bring Spring dependencies attached.
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>
I am creating my first SAP UI5 app and I have a need where i want to set an additional property to the data returned from an Odata service before i set it as a model to in the table view
However i am unable to access the data as the getProperty returns an empty object. Below is the code on the onInit() method of my controller . I am obtaining the model from my manifest.json as it looks a clean way to do things.
var rList = this.getOwnerComponent().getModel("Entities");
var localPromise = this.getPromise(rList, "/");
localPromise.done(function() {
console.log(rList.getProperty("/"));
// here i would like to do the manipulations and then set the view
}.bind(this));
},
i assume the getPromise method must take care of the asynchronous execution part:
getPromise: function(oModel, pathToTestForData) {
var deferred = $.Deferred();
if (oModel.getProperty(pathToTestForData))
deferred.resolve(); //Data already loaded
else
oModel.attachRequestCompleted(deferred.resolve); //Waiting for the event
return deferred.promise();
}
What i want to do is the following:
1) make the Odata two way bind.
2) set another property : anotherProperty : false on each returned Odata record
However as rList.getProperty("/") inside the done of the promise is empty, i am at a roadblock, Also how to access the data (if it was there)
I have a web application in which I am using DataTable version 1.10 to display the records and for pagination. I am new to DataTable. I am finding it difficult in capturing the parameters like search string in the search box of data table, Sort action,iTotalRecords,iTotalDisplayRecords,iDisplayLength etc etc.,
I am using struts2 for my web application. I have enabled the bServerSide=true; and calling "sAjaxSource" : "PaginationAction". the records private List<Income> aaData; are getting populated in jsp page. But I am finding it difficult to capture the other parameters as specified above. to which action class's variable does this entered string goes to.? I have a variable private String search; in my action class to which I am expecting the search box string should be assigned.
Please help me which this. Do I need to add any jar files of datatable1.10 version to my project( I am not sure If we have any jar).
Here is my JQuery Code:
var oTable=$(".IncomeTable").dataTable({
"paging":true,
"searching": true,
"bProcessing" : true,
"bServerSide" : true,
"bJQueryUI" : true,
"info":true,
"bAutoWidth": false,
"iDisplayLength": 10,
"aLengthMenu": [[10, 15], [10, 15]],
"sPaginationType" : "full_numbers",
"ajax" : "PaginationAction",
"aoColumns": [
{"mData":"description","bSearchable": true,"bSortable": true},
{"mData":"catergory.userCodeName","bSearchable": false,"bSortable": false},
{"mData":"payee.payeeName","bSearchable": false,"bSortable": false},
{"mData":"transactionDate","bSearchable": false,"bSortable": false},
{"mData":"amount","sWidth":"30px","bSearchable": false,"bSortable": false}]
});
Action Class variables:
private int iTotalRecords;
private int iTotalDisplayRecords;
private int iDisplayLength;
private String sEcho;
private String sColumns;
private String sSearch;
private String search;
private String sKeyword;
private List<Income> aaData;
Note: all the integer values are coming as '0' and string variables as null
After several days of Google search, My version of conclusion for the above post is as below.
Conclusion: Strut2 will not automatically populate the values of datatable properties to action class's property. But the dataTable properties that are sent from the jsp page can be captured using the HttpServletRequest object. See the below code
HttpServletRequest request=ServletActionContext.getRequest();
String searchFilterString=request.getParameter("search[value]");
// here String 'search[value]' is the parameter name sent by datatable
Here is the link to the list of parameters sent to server from datatables and parameters sent from server to datatable
Below is the piece of java Code which I have used to trim the List to support my datatable records.
int fromIndex=0,toIndex=0;
int length=Integer.parseInt(request.getParameter("length");
int start=Integer.parseInt(request.getParameter("start");
int iDisplayLength=Integer.parseInt(request.getParameter("iDisplayLenght");
if(length>0)
{
fromIndex=(int)(Math.ceil((start+1)/lenght)*length);
toIndex=fromIndex+length;
}
else
{
fromIndex=(int)(Math.ceil((start+1)/iDisplayLength)*iDisplayLength);
toIndex=fromIndex+iDisplayLength;
}
if(toIndex>getAaData().size())
{
toIndex=getAaData().size();
}
setAaData(getAaData().subList(fromIndex,toIndex));
Let me know if any one have any doubts regarding the above post and my version of answer. I haven't done any change to the above mentioned JQuery code.
Any corrections and suggestion for the above post are greatly appreciated
Note: Different parameters will be passes to server if you are usingsAjaxSource in stead of ajax in the jquery Code. You can get to know about the parameters of datatable in request object.
My goal is to persist a simple relationship between two breeze entities on my OData server.
I've setup a server, I am able to:
insert data
query data
create a relation between two entities client-side
BUT not able to persist the relationship server-side.
Any ideas of what I'm missing?
Below is my setup details
I'm using OData/MongoDB backend running JayData on Node.js (virtualBox, ubuntu 12.04, node.js, MongoDB)
I have created a simple data model with a user and a person entity based on this stack overflow question. This is the JayData datamodel definition
>
$data.Class.define("$org.Types.user", $data.Entity, null, {
Id: {type: "id", key: true, computed: true, nullable: false },
Person: { type: "$org.Types.person", inverseProperty: "User", required:true },
EmailAddress: { type: "string"},
Password: { type: "string"}
}, null)
$data.Class.define("$org.Types.person", $data.Entity, null, {
Id: {type: "id", key: true, computed: true, nullable: false },
User: { type: "$org.Types.user", inverseProperty: "Person"},
FirstName: { type: "string"},
LastName: { type: "string"}
}, null);
$data.Class.defineEx("$org.Types.Context", [$data.EntityContext, $data.ServiceBase], null, {
User: {type: $data.EntitySet, elementType: $org.Types.user } ,
Person: {type: $data.EntitySet, elementType: $org.Types.person }
});
exports = $org.Types.Context;
I'm able to query the data using Breeze.js
I'm able to insert User and Person entities using Breeze.js
I'm able to set a relation in Breeze and I see the changes to the entities
I've updated Breeze.js to 1.3.3
>
var manager = new breeze.EntityManager('api/');
// other breeze initialization stuff, metadata etc.
var person = manager.createEntity('Person', undefined, breeze.EntityState.Detached);
var user = manager.createEntity('User', undefined, breeze.EntityState.Detached);
// set other fields, name, email, password
user.Person(user);
manager.addEntity(user);
manager.addEntity(person);
// save the changes
manager.saveChanges().then(function() { // etc
But I only see two OData post for the two entities but nothing to tie the two entities together
I ruled out the OData adapter as both the WebAPI and OData adapter call the same functions in the Breeze code base and there are multiple Breeze/WebAPI that demonstrate the ability to query and inserted related entities.
I haven't seen a Breeze.js / OData sample that seems to address this.
The closest example that works is a datajs code sample. It posts the related entity to /$links/ to create the relationship (something I don't see in the OData adapter of neither Breeze.js or JayData).
I've never used Breeze with JayData server, but I've been using JayData client library to save data over OData for a year and it works with static schema (you generate it with JaySvcUtil) and dynamic schema (grabs the metadata from the server in runtime) as well.ű
To important things:
use typed entites, not POCO objects
set the required side of the relationship to have the items persisted
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://include.jaydata.org/datajs-1.0.3.min.js"></script>
<script src="http://include.jaydata.org/jaydata.js"></script>
<script>
var url = 'http://localhost:54001/personService';
$data.service(url, function(contextFactory, contextType){
var db = contextFactory();
db.onReady(function(){
var user = new db.User.elementType({ EmailAddress: 'joe.smith#company.org'});
var person = new db.Person.elementType({ FistName: 'Joe', LastName: 'Smith', User: user }); //set the value to the required side of the relationship to have your entities saved in the batch
db.Person.add(person)
db.saveChanges(function () {
db.Person.include('User').toArray(function (p) { console.log(p);});
});
})
});
disclaimer: I'm member of the JayData dev team, so you can help you with the server-side, too.