Access OData JSON model mock file vs SAP backend - arrays

I have an application that works for test purposes with local JSON mock data. The oData Object contains arrays with values and the application works as desired.
Now we are switching from the local mock data File to data consumption with an oData service from a SAP backend system.
Here I get the data in JSON Objects and not all the functionality works as desired (example filter functions).
Can somebody share some thoughts about JSON Objects and Arrays with me?
And how can I get the data from the backend system in an array instead of an object?
In the mock data version I do this to define my model:
this._oModel = new JSONModel(jQuery.sap.getModulePath("myApplication", "/localService/mockdata/nodesSet.json"));
In the oData Version the model is defined in manifest.json:
this._oModel = this.getOwnerComponent().getModel();
Note: I am aware of the different names of the entities (example: nodes vs nodesSet) and this is not part of the problem.
Thanks!

One simple way would be not to create the model in the Manifest and do an explicit read in the controller as:
var oModel = new sap.ui.model.odata.v2.ODataModel(url, true);
that=this;
oModel.read( "/Products", {
urlParameters: {
"$skip": 0,
"$top": 50
},
success: function( oData) {
//here oData shall have an array of objects "results"
**-------------Set the model here using this array -> results ------**
},
error: function(oError) {
alert("error");
}
});
I am however not proud of this solution and will check if I can comment better.

Related

filter mongoose documents based on the specific fields and attributes

I'm developing a website using the MEAN stack (MongoDB/Express/Angular/Node).
I have a product schema with 12 different fields/properties, including size, color, brand, model, etc. What is the best and most efficient way to filter products, in Angular or on the server-side?And how can i chain the results if the client had selected more than one property?What would that look like?
Assuming there will be a lot of products, it will be too much to download to the client in order to filter using Angular. It doesn't scale very well. As the list of products gets bigger and bigger, it will be less and less performant. The better way would, generally, be to let MongoDB do the filtering for you. It's very fast.
But, you can control the filtering from Angular by posting to the server the filtering term you want on the endpoint used for that method of filtering, for example, using the http module
http.post('/api/filter/' + methodOfFiltering, { 'term': termtoFilterBy }, function(dataReturned) {
// use dataReturned to do something with the data
});
Put this in an angular service method, so you can inject it into any of your controllers/components.
Create an endpoint that will use the method and the keyword in the mongoose query. I'm assuming that you're using Express for your server routes.
app.post('/api/filter/:method', function(req, res) {
var method = req.params.method;
var termToFilterBy = req.body.term;
productSchema.find({method: termToFilterBy}, function(err, products) {
res.send(products);
});
});
Let me know if this helps.

Cloud Endpoints not accepting JSON array

I want to build my endpoint, which accept JSON array of below format:
[
{
"test":"Math",
"result":"Pass"
},
{
"test":"Science",
"result":"FirstClass"
}
]
It will be a POST call with the above JSON to my endpoint.
I tried it with servlet too but did not get the required result, and also tried to with list and inserting in a new class and posting to that class. Thanks in advance.
Is that an accurate representation of the JSON object which is being sent over? Because one does not simply send a a POST request with a JSON object of their param object to a cloud endpoint. See here for a thorough guide to Endpoint API interaction from a javascript perspective - notice how the client library exposes an object "gapi" through which calls are made. If you're sending this JSON from an iOS or Android app, there are similar client libraries which can be generated for you by a cloud endpoints build tool.
After much frustration, I resorted to reading the docs more carefully. In that quest, I found an important note in the doc:
https://cloud.google.com/endpoints/docs/frameworks/java/parameter-and-return-types
"Any type except a parameter or injected type is considered an entity type. ... Entity types cannot be annotated with #Named"
With all examples showing named parameters, I was stumped as the docs don't explain further, but then found a solution. It ends up that if you do not have named parameters, everything is just passed in as a LinkedHashMap. Usually, you can do any work you need to with just that data structure, but if you HAVE to have it in JSON, you can convert it. Here are some examples:
#ApiMethod(name = "endpointIterfaceName.createItems", httpMethod = "post", path = "test/items")
public WhateverReturnType createItems(LinkedHashMap<String, Object> itemsMap) {
// Do Stuff with map values
return whateverReturnValue;
}
With this, you need to be sure that you post your data with the Content-Type of json (i.e. Content-Type:application/json; charset=UTF-8). So, for example, when testing, with a jquery ajax call you would need to set dataType to "json" or with Postman, you would select "Raw" then JSON (application/json).
If you really want to convert this to a JSON object in Java because for whatever reason you can not use a hash map, you can do the following in your method:
// Use gson library to convert the map to a string
Gson gson = new Gson();
String mapAsJsonString = gson.toJson(itemsMap);
// create a JSON object from the new string representation
JSONObject obj = new JSONObject(mapAsJsonString);
As a side note, if this is passed as Content-Type:text then the whole body will be in the map as the first key of the map. You could do some inadvisable things here and just get that key and avoid converting the map to a string and then to a json object, but, like I said, that is inadvisable. :)

ExtJs Model Proxy vs. Store Proxy

OK, I'm stuck on what should be a basic task in ExtJs. I'm writing a simple login script that sends a user name and password combination to a RESTful web service and receives a GUID if the credentials are correct.
My question is, do I use a Model Proxy or a Store Proxy?
To my understanding, Models represent a single record, whereas Stores are for handling sets of data containing more than one record. If this is correct then it would seem that a Model proxy is the way to go.
Following Sencha's documentation at http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.data.Model the code would look something like this:
Ext.define('AuthenticationModel', {
extend: 'Ext.data.Model',
fields: ['username', 'password'],
proxy: {
type: 'rest',
url : '/authentication'
}
});
//get a reference to the authentication model class
var AuthenticationModel = Ext.ModelManager.getModel('AuthenticationModel');
So far everything is OK, until the next step:
//Use the configured RestProxy to make a GET request
AuthenticationModel.load('???', {
success: function(session) {
console.log('Login successful');
}
});
The load() method for the Model class is a static call expecting a single unique identifier. Logins typically depend upon two factors, username and password.
So it appears Store proxies are the only way to validate someone's username and password credential combination in ExtJS. Can someone verify and explain? Any help to understand this would be greatly appreciated.
You just need to know the following:
The store will use it's own proxy if you configured one for this
instance and if not he takes the proxy from the model.
So you can easily go with two proxy configurations to enable the multi-CRUD operations on the store and the single-CRUD operations on the Models. Note the the static load method of the Model expects the model id because it is supposed to load a model by just one Id (yes, composite keys are not supported). You will also have to fetch the model instance in the callback (As you did).
Back to your Username/password problem
You may apply your session Model with a custom 'loadSession' method
loadSession: function(username,password, config) {
config = Ext.apply({}, config);
config = Ext.applyIf(config, {
action: 'read',
username: username,
password: password
});
var operation = new Ext.data.Operation(config),
scope = config.scope || this,
callback;
callback = function(operation) {
var record = null,
success = operation.wasSuccessful();
if (success) {
record = operation.getRecords()[0];
// If the server didn't set the id, do it here
if (!record.hasId()) {
record.setId(username); // take care to apply the write ID here!!!
}
Ext.callback(config.success, scope, [record, operation]);
} else {
Ext.callback(config.failure, scope, [record, operation]);
}
Ext.callback(config.callback, scope, [record, operation, success]);
};
this.getProxy().read(operation, callback, this);
}
Now call this instead of load.
I found it in the documentation of sencha App Architecture Part 2
Use proxies for models:
It is generally good practice to do this as it allows you to load and
save instances of this model without needing a store. Also, when
multiple stores use this same model, you don’t have to redefine your
proxy on each one of them.
Use proxies for stores:
In Ext JS 4, multiple stores can use the same data model, even if the
stores will load their data from different sources. In our example,
the Station model will be used by the SearchResults and the Stations
store, both loading the data from a different location. One returns
search results, the other returns the user’s favorite stations. To
achieve this, one of our stores will need to override the proxy
defined on the model.

Partial Updates (aka PATCH) using a $resource based service?

We're building a web application using Django/TastyPie as the back-end REST service provider, and building an AngularJS based front end, using lots of $resource based services to CRUD objects on the server. Everything is working great so far!
But, we would like to reduce the amount of data that we're shipping around when we want to update only one or two changed fields on an object.
TastyPie supports this using the HTTP PATCH method. We have defined a .diff() method on our objects, so we can determine which fields we want to send when we do an update. I just can't find any documentation on how to define/implement the method on the instance object returned by $resource to do what we want.
What we want to do is add another method to the object instances, (as described in the Angular.js documentation here) like myobject.$partialupdate() which would:
Call our .diff() function to determine which fields to send, and then
Use an HTTP PATCH request to send only those fields to the server.
So far, I can't find any documentation (or other SO posts) describing how to do this, but would really appreciate any suggestions that anyone might have.
thank you.
I would suggest using
update: {
method: 'PATCH',
transformRequest: dropUnchangedFields
}
where
var dropUnchangedFields = function(data, headerGetter) {
/* compute from data using your .diff method by */
var unchangedFields = [ 'name', 'street' ];
/* delete unchanged fields from data using a for loop */
delete data['name'] ;
delete data['street'];
return data;
}
PS: not sure from memory, whether data is a reference to your resource of a copy of it, so you may need to create a copy of data, before deleting fields
Also, instead of return data, you may need return JSON.stringify(data).
Source (search for "transformRequest" on the documentation page)
We implemented $patchusing ngResource, but it's a bit involved (we use Django Rest Framework on the server-side). For your diff component, I'll leave to your own implementation. We use a pristine cache to track changes of resources, so I can poll a given object and see what (if any) has changed.
I leverage underscore's _.pick() method to pull the known fields to save off the existing instance, create a copy (along with the known primary key) and save that using $patch.
We also use some utility classes to extend the built-in resources.
app.factory 'PartUpdateMixin', ['$q', '_', ($q, _) ->
PartUpdateMixin = (klass) ->
partial_update: (keys...) ->
deferred = $q.defer()
params = _.pick(#, 'id', keys...)
o = new klass(params)
o.$patch(deferred.resolve, deferred.reject)
return deferred.promise
]
Here's the utility classes to enhance the Resources.
app.factory 'extend', ->
extend = (obj, mixins...) ->
for mixin in mixins
obj[name] = method for name, method of mixin
obj
app.factory 'include', ['extend', (extend) ->
include = (klass, mixins...) ->
extend klass.prototype, mixins...
return include
]
Finally, we can enhance our Resource
include TheResource, PartUpdateMixin(TheResource)
resourceInstance = TheResource.get(id: 1234)
# Later...
updatedFields = getChangedFields(resourceInstance)
resourceInstance.partial_update(updatedFields...)
I would suggest using Restangular over ngResource. The angular team keeps improving ngResource with every version, but Restangular still does a lot more, including allowing actions like PATCH that ngResource doesn't. Here'a a great SO question comparing the two What is the advantage of using Restangular over ngResource?

Cannot see the Restangular response data set in my chrome developer tools... is it bc my JSON contains nested JSON?

I'm currently trying to get a basic RESTful service up that pulls my JSON objects from MongoLab rather than the file-based implementation which I had working in my sandbox. Each of my JSON objects contain a child array (their predecessor IDs):
{title: 'xxyy1', course_id: '10004', semester_hours: 3, detail: 'coursename1', predecessors: ['10001']},
{title: 'xxyy2', course_id: '10005', semester_hours: 3, detail: 'coursename2', predecessors: ['10001','10003','10004']},
{title: 'xxyy3', course_id: '10006', semester_hours: 3, detail: 'coursename3', predecessors: ['10001','10003','10004']},
{title: 'xxyy4', course_id: '10007', semester_hours: 3, detail: 'coursename4', predecessors: ['10004','10006']}
This works perfectly fine when stringing this up into angularJS, by simply pulling the course.title, course.course_id, etc. into an ng-repeat. Even the predecessors easily is managed by constructing it as direct JSON.
<span class="predecessors">{{course.predecessors | json}}</span>
However, when trying to pull this same dataset from MongoLab using Restangular as my resource provider, I'm unable to see any data responded in the view... actually, I cannot see any data anywhere. Using Chrome's dev tools, all I see is the following:
![Restangular Response]: http://imgur.com/w8qE96K.jpg
Am I missing something here? My Mongo implementation is as follows:
RestangularProvider.setRestangularFields({
id: 'course_id'
});
RestangularProvider.setListTypeIsArray(false);
RestangularProvider.setResponseExtractor(function(response, operation, what, url) {
var newResponse;
if (operation === "getList" && what === "availableCourses") {
console.log(response);
newResponse = response.data.title;
newResponse.course_id = response.data.course_id;
newResponse.semester_hours = response.data.semester_hours;
newResponse.detail = response.data.detail;
newResponse.predecessors = response.data.predecessors;
} else {
newResponse = response.data;
}
return newResponse;
});
I'm the creator of Restangular.
So, when you're doing a getList, Restangular expects to get an Array as the response. In your case, when you're getting a list and the path is availableCourses, you're returning a string (the title) which has properties. So you're creating a "special" string with properties, it's not really common, nor compatible with Restangular.
If you want to get the list of all available courses, you need to return an array as the new response. So, what's the exact response from the server when you do the getList? If you giv eme that, I'll be able to help you easier on how to create this response extarctor.
Also take a look to this MongoLab example :), maybe It'll help you.
http://plnkr.co/edit/d6yDka?p=preview
Bests!

Resources