How to map data mapping in Angular $resource - javascript

Take the following example from Angular's docs:
var CreditCard = $resource('/user/:userId/card/:cardId',
{userId:123, cardId:'#id'}, {
charge: {method:'POST', params:{charge:true}}
});
// We can retrieve a collection from the server
var cards = CreditCard.query(function() {
// GET: /user/123/card
// server returns: [ {id:456, number:'1234', name:'Smith'} ];
What is the correct way to map the data structure, an onject with 3 properties in this example, that returns from the server, without the need to "guess" the structure. see the comment "// server returns.. " - I don't want to assume that, but to have a more structural way, like an expected interface or something alike.
How do you map data in angular than ?

Related

How to rename field from object

I'm using Angular 5.
I have "fake back-end" (array of items).
My case:
I'm waiting for the following structure of object:
id: number,
title: string
But, Back-End sends me wrong structure:
id: number,
name: string.
I need to receive data from back-end, and if field name (in my case "name" is wrong, should be "title") is wrong, I should RENAME field and return valid object.
P.S. I have interface and class
Good practice on large apps where you don't have much control over the backend is to create a mapper for each response type you expect.
For example you make an http request to retrieve a list of cars from your backend.
When you retrieve the response, you pass the data to a specific mapping function.
class CarMapper {
// map API to APP
public serverModelToClientModel(apiModel: CarApiModel): CarAppModel {
const appModel = new CarAppModel(); // your Car constructor
// map each property
appModel.id = apiModel.id_server;
appModel.name = apiModel.title;
return appModel; // and return YOUR model
}
}
This way on the client side you always have the correct data model. And you adapt on any model change made on the backend.
You can check if an object has name key and then create another object with title
if (obj.hasOwnProperty("name")){
var newObj = {
id: obj.id,
title: obj.name
};
}
obj = newObj;

Backbone: I am trying to fetch a collection (using a rails server). However, my fetch doesn't look to be working right

I am using a rails server that returns this JSON object when going to the '/todos' route.
[{"id":1,"description":"yo this is my todo","done":false,"user_id":null,"created_at":"2015-03-19T00:26:01.808Z","updated_at":"2015-03-19T00:26:01.808Z"},{"id":2,"description":"Shaurya is awesome","done":false,"user_id":null,"created_at":"2015-03-19T00:40:48.458Z","updated_at":"2015-03-19T00:40:48.458Z"},{"id":3,"description":"your car needs to be cleaned","done":false,"user_id":null,"created_at":"2015-03-19T00:41:08.527Z","updated_at":"2015-03-19T00:41:08.527Z"}]
I am using this code for my collection.
var app = app || {};
var TodoList = Backbone.Collection.extend({
model: app.Todo,
url: '/todos'
});
app.Todos = new TodoList();
However, when trying to fetch the data it states that the object is undefined. I originally thought that my function wasn't parsing the JSON correctly. However, that doesn't look to be the case. I created a parse function with a debugger in it to look at the response. In gives back, an array with three objects.
Here what happens when I try testing the fetch().
var todos = app.Todos.fetch()
todos.length // returns undefined
todos.get(1) // TypeError: undefined is not a function
The todos collection doesn't automatically populate the function get() in console. I am running out of ideas of what can be the problem. Please help. Thanks!
Fetch is a ayncronous, you need to listen to the add event:
var todos = app.Todos.fetch()
todos.on('add', function(model){
console.log(todos.length);
});
If you pass the parameter reset, you could listen for the would new models:
var todos = app.Todos.fetch({reset: true})
todos.on('reset', function(model){
console.log(todos.length);
});
You could also read here.
There are two problems:
Fetch is asynchronous; we don't know exactly when we'll have a result, but we do know that it won't be there when you are calling todos.length.
Fetch sets the collection's contents when it receives a response; calling app.Todos.fetch() will result in app.Todos containing whatever models were fetched by the request. Its return value is not useful for inspecting the collection, so var todos = app.Todos.fetch() won't give you what you want in any case.
If you want to inspect what you receive from the server, your best option is to set a success callback:
app.Todos.fetch({
success: function (collection, response, options) {
console.log(collection);
}
});

Dojo JsonRestStore with array not at root-level of JSON response

Is there a way to configure a JsonRestStore to work with an existing web service that returns an array of objects which is not at the root-level of the JSON response?
My JSON response is currently similar to this:
{
message: "",
success: true,
data: [
{ name: "Bugs Bunny", id: 1 },
{ name: "Daffy Duck", id: 2 }
],
total: 2
}
I need to tell the JsonRestStore that it will find the rows under "data", but I can't see a way to do this from looking at the documentation. Schema seems like a possibility but I can't make sense of it through the docs (or what I find in Google).
My web services return data in a format expected by stores in Ext JS, but I can't refactor years worth of web services now (dealing with pagination via HTTP headers instead of query string values will probably be fun, too, but that's a problem for another day).
Thanks.
While it's only barely called out in the API docs, there is an internal method in dojox/data/JsonRestStore named _processResults that happens to be easily overridable for this purpose. It receives the data returned by the service and the original Deferred from the request, and is expected to return an object containing items and totalCount.
Based on your data above, something like this ought to work:
var CustomRestStore = declare(JsonRestStore, {
_processResults: function (results) {
return {
items: results.data,
totalCount: results.total
};
}
});
The idea with dojo/store is that reference stores are provided, but they are intended to be customized to match whatever data format you want. For example, https://github.com/sitepen/dojo-smore has a few additional stores (e.g. one that handles Csv data). These stores provide good examples for how to handle data that is offered under a different structure.
There's also the new dstore project, http://dstorejs.io/ , which is going to eventually replace dojo/store in Dojo 2, but works today against Dojo 1.x. This might be easier for creating a custom store to match your data structure.

BackboneJS collection.reset() vs collection.fetch()

I have read and read the docs on these two methods, but for the life of me cannot work out why you might use one over the other?
Could someone just give me a basic code situation where one would be application and the other wouldn't.
reset sets the collection with an array of models that you specify:
collection.reset( [ { name: "model1" }, { name: "model2" } ] );
fetch retrieves the collection data from the server, using the URL you've specified for the collection.
collection.fetch( { url: someUrl, success: function(collection) {
// collection has values from someUrl
} } );
Here's a Fiddle illustrating the difference.
We're assuming here that you've read the documentation, else it'l be a little confusing here.
If you look at documentation of fetch and reset, what it says is, suppose you have specified the url property of the collection - which might be pointing to some server code, and should return a json array of models, and you want the collection to be filled with the models being returned, you will use fetch.
For example you have the following json being returned from the server on the collection url:
[{
id : 1,
name : "a"
}, {
id : 2,
name : "b"
}, {
id : 3,
name : "c"
}]
Which will create 3 models in your collection after successful fetch. If you hunt for the code of collection fetch here you will see that fetch will get the response and internally will call either reset or add based on options specified.
So, coming back to discussion, reset assumes that we already have json of models, which we want to be stored in collection, we will pass it as a parameter to it. In your life, ever if you want to update the collection and you already have the models on client side, then you don't need to use fetch, reset will do your job.
Hence, if you want to the same json to be filled in the collection with the help of reset you can do something like this:
var _self = this;
$.getJSON("url", function(response) {
_self.reset(response); // assuming response returns the same json as above
});
Well, this is not a practice to be followed, for this scenario fetch is better, its just used for example.
Another example of reset is on the documentation page.
Hope it gives a little bit of idea and makes your life better :)
reset() is used for replacing collection with new array. For example:
#collection.reset(#full_collection.models)
would load #full_collections models, however
#collection.reset()
would return empty collection.
And fetch() function returns default collection of model

Backbone.js fetch not actually setting attributes

I have a basic backbone model, its urlRoot attribute is set and the corresponding target on the server side returns a correct JSON output (both JSON string and application/json header).
I call a fetch like this:
var athlete = new Athlete({ id: 1 });
athlete.fetch();
at this point if I add a
console.log(athlete);
I can see the model, and inspecting it in firebug I can open the attributes object and see all the values returned from the server.
BUT if I do a:
console.log(athlete.get('name'));
I get undefined (the name appears under the attributes in the DOM inspection I mentioned above)
also doing a:
console.log(athlete.attributes);
returns an object containing only {id: 1} which is the argument I passed while creating the model.
If I create the model like this:
var athlete = new Athlete(<JSON string copypasted from the server response>);
then everything works fine, the .get() method returns whatever I ask, and athlete.attributes shows all the values.
What am I doing wrong?
fetch is asynchronous, which means that the data won't be available if you immediatly call console.log(athlete.get('name')) after the fetch.
Use events to be notified when the data is available, for example
var athlete = new Athlete({id: 1});
athlete.on("change", function (model) {
console.log(model.get('name'));
});
athlete.fetch();
or add a callback to your fetch
var athlete = new Athlete({ id: 1 });
athlete.fetch({
success: function (model) {
console.log(model.get('name'));
}
});
or take advantage of the promise returned by fetch:
athlete.fetch().then(function () {
console.log(athlete.get('name'));
});
Just as a quick remark when using events in this example. It did not work with change in my case because this events fire on every change. So sync does
the trick.
var athlete = new Athlete({id: 1});
athlete.on("sync", function (model) {
console.log(model.get('name'));
});
athlete.fetch();

Categories