Ember RESTAdapter with custom JSON format - javascript

I'm currently enjoying diving into Ember and learning a complete Front End MVC solution.
Currently, I'm a little stumped on getting data from our API as it doesn't follow the standard required by Ember's Adapter. Currently, our team are unable to change the structure of the API / JSON response due to the dependencies of third party applications.
RESTAdapter is looking for JSON like this:
{
'episodes' : [
{
id : '1',
title : 'my first title'
}
]
}
Unfortunately all we get back is an array with each episode as an object, i.e. it cannot be a key with a value of array of objects.
[
{
id : 1,
title : 'my first title'
},
{
id : 2,
title : 'my second title'
}
]
Can anyone provide assistance on how to extend DS.RESTAdapter to follow this format?
Again, our server devs cannot change the API so we have to take the JSON response as is.
Thanks

Override extractArray in your serializer. You can then modify the payload to match what ember data is looking for.
App.ApplicationSerializer = DS.RESTSerializer.extend({
extractArray: function(store, type, payload){
var plural = Ember.String.pluralize(type.typeKey),
fixed = {};
fixed[plural] = payload;
return this._super(store, type, fixed);
}
});
Example: http://emberjs.jsbin.com/OxIDiVU/953/edit

Related

GitHub GraphQL API query for response simplification [duplicate]

Let's say I've got a GraphQL query that looks like this:
query {
Todo {
label
is_completed
id
}
}
But the client that consumes the data from this query needs a data structure that's a bit different- e.g. a TypeScript interface like:
interface Todo {
title: string // "title" is just a different name for "label"
data: {
is_completed: boolean
id: number
}
}
It's easy enough to just use an alias to return label as title. But is there any way to make it return both is_completed and id under an alias called data?
There is no way to do that. Either change the schema to reflect the client's needs or transform the response after it is fetched on the client side.

How to correctly parse the JSON?

I have developed a Cordova android plugin for my library. The library is used for sending events across different connected devices.
JS interface receives a JSON from the java side. What I want to do is to parse this before reaching the application so that the developer can directly use it as a JS object. When I tried to parse the JSON in my plugin's JS interface, I am running into issues. Below is an example:
Received by JS interface:
{"key":"name","data":"{\"name\":\"neil\",\"age\":2,\"address\":\"2 Hill St\"}"}
After parsing in JS interface:
Object {key: "name", data: "{"name":"neil","age":2,"address":"2 Hill St"}"}
data:"{"name":"neil","age":2,"address":"2 Hill St"}"
key:"name"
__proto__:Object
As you can see, if this data reaches the app and the developer accesses the data:
eventData.key = name;
eventData.data = {"name":"neil","age":2,"address":"2 Hill St"};
eventData.data.name = undefined
How can I parse the inner data as well in my JS interface so that the developer can access directly. In the above case, he has to parse eventData.data to access the properties. I don't want this to happen and I want to do this in JS interface itself.
Please note that eventData can have many properties and hence they should be properly parsed before passing into the app.
I am new to Javascript and hence finding it difficult to understand the problem.
It seems that your returned JSON contains a string for the data property.
var response = {"key":"name","data":"{\"name\":\"neil\",\"age\":2,\"address\":\"2 Hill St\"}"};
//Parse the data
var jsonData = JSON.parse(response.data);
console.log(jsonData.name); //neil
console.log(jsonData.age); //2
console.log(jsonData.address);//"2 Hill St"
As others pointed out, you have to do JSON.parse(eventData.data) as the data comes as a string.
You have to look why that happens. The inner data might be stored in this way, in some cases its valid to store it in db as flat object or it is stringified twice by mistake:
var innerdata = JSON.stringify({ name: "neil" });
var eventData = JSON.stringify({ key: "name", data: innerdata });
would correspond to your received string.
Correct way to stringify in first place would be:
var innerdata = { name: "neil" };
var eventData = JSON.stringify({ key: "name", data: innerdata });

Convert JSON naming schema in Ember

I have an application where I retrieve JSON data from a server. Unfortunately the JSON data is formatted as such:
"Product_Group" : [
{
"Product_Group_ID" : "396xx",
"Product_Group_SEO_Copy" : "Not Included in JSON",
"Product_Group_Title" : "Some awesome Title",
"Products" : [
{
"On_Sale_Date" : "04\/28\/09 00:00:00.000",
"ISBN" : "97800617737xx",
"Title" : "A Disgraceful Affair",
//rest of the it follows
Ember throws errors when trying to use Capitalized JSON objects in a template. Specifically the Uncaught TypeError: Cannot read property 'unchain' of undefined error. This is related to this issue noted on the Github Ember site.
My question, how can I convert all the titles from the server into camelCase? I don't have access to the server to change things on that end, so it will have to be client side. I've looked into the DS.RESTSerializer but I don't understand it enough to know if that is what I should be using.
DS.RESTSerializer is exactly what you want to use. You can easily transform the keys of your attributes by using the keyForAttribute hook. You may also need to change the attribute name of your root node Product_Group to something like productGroup. You can do this with extractArray.
A serializer such as this might just do the trick:
App.ProductGroupSerializer = DS.RESTSerializer.extend({
extractArray: function(store, type, payload) {
return this._super(store, type, {
productGroup: payload['Product_Group']
});
},
keyForAttribute: function(attr) {
return Ember.String.camelize(attr);
}
});

Extjs 3.4 custom JSONReader

I haven't had a question from quite a while, but I finally ended up hitting a wall here. Anyways, to make this easy. I am trying to create a JSON store in extjs 3.4 (work related, and no I am not updating).
Well, I created the queries as usual with the proper response and fill it up. My problem is that I have 1 extra property on the JSON that I want to be able to pull and use on the app.
Sample of my JSON from the response object in chrome:
myInventory: [{Priority:1, PMNumber:444, Description:fix-a-tape, Assets:3, Storage_Count:0,…},…]
percent: 97.040498442368
totalCount: "3"
Now, I know this is correctly formatted because the Grid I am using gets populated, but I can't get the percent property. So my question is, how do you pull an extra parameter on the datastore building block of code when you have one extra parameter that is not usual on EXTjs, in my case the percent?
I tried doing a metachange on the JSONReader, but all I get is percent:"percent" on the properties as I inspect the datastore after it's creation.
Ext.data.JsonReader has a property jsonData which is exactly what you need. A quick example:
Ext.onReady(function() {
var store = new Ext.data.JsonStore({
url: 'data/test.json',
root: 'dataRoot',
fields: ['fieldA', 'fieldB'],
idProperty: 'id',
storeId: 'myStore'
});
store.on('load', function(store) {
console.log(store.reader.jsonData.someOtherProperty);
});
store.load();
});
and the data/test.json looks like this:
{
dataRoot: [{
id: 0,
fieldA: 'a',
fieldB: 'b'
}],
someOtherProperty: 'abc'
}
There could also be an alternative approach that you manually (not via store.load()) perform Ext.Ajax request, use the properties you need and then manually call Ext.data.JsonStore.loadData() using the data you got from Ajax request.

Backbone relational lazy loading

I'm using Backbone with my RESTful JSON API in order to create an app that works with posts and their comments. I've been trying to get Backbone Relational to work, but run into problems with my Lazy loading.
I load up a list of posts, without the related comments. On click of an post in the list, I open up a view that fetches the full Post, comments included, and renders this.
I've got 2 Backbone.RelationModels, Posts and Comments. The post relation to the comment is setup as folows:`
relations: [{
type: Backbone.HasMany,
key: 'comments',
relatedModel: 'Comment',
includeInJSON: true, // don't include it in the exporting json
collectionType: 'Comments'
}]
Now the problem I'm facing is that the relationships are initialized as soon as I retrieve my list, that do not contain the comments yet. I load up the full data later, by fetching the model by it's URI. However, the relationships don't seem to reinitialise, calling Posts.get(1).get('comments') returns a Comments collection that is empty!
Does anyone know how I could best tackle this problem? The data is there, it just seems the collection of the comments doesn't gets updated.
Edit: I can make the Post model bind it's change:comments to itself, which updates the collection. However, I can't seem to find a solid way to get the original comments' JSON, since this.get('comments') returns the Comments collection.
Note: In my collection, I do parse the JSON to make it work with my API, with the following code:
parse: function(response) {
var response_array = [];
_.each(response, function(item) {
response_array.push(item);
});
return response_array;
}
This is because the JSON returned by my API returns an object with indexed keys (associative array) instead of a native JSON array.
{
"id" : "1",
"title" : "post title",
"comments" : {
"2" : {
"id" : "2",
"description": "this should solve it"
},
"6" : {
"id" : "6",
"description": "this should solve it"
}
}
}
Thanks a bunch! Please ask any questions, I'm sure I've been vague somewhere!
The Backbone Relational model doesn't parse collections other then arrays, the JSON from my question didn't work. I changed the backend to return the comments in a proper array
{
"id" : "1",
"title" : "post title",
"comments" : [
{
"id" : "2",
"description": "this should solve it"
},
{
"id" : "6",
"description": "this should solve it"
}]
}
}
The RelationalModel doesn't respect the parse function that Backbone provides to parse your JSON before it moves on. With the backend returning "proper" JSON, the lazy loading works without any extra code.
You can also use the initialize method on your comment model, to simulate the parse method and define attributes with custom values like this (CoffeeScript):
initialize: (obj) ->
#attributes = obj.customKey

Categories

Resources