Angular $resource save an object containing arrays - javascript

Let's say we have a Person $resource that looks like this:
$scope.person = {
name: 'Max',
friends: [1, 2, 3]
}
If we Person.save($scope.person) to server, it would send the following parameters:
name: 'Max'
friends: '1'
friends: '2'
friends: '3'
So I will not have access to the array of friends on the server. Only its last element would be accessible.
What is the correct way of saving objects containing arrays to server using $resource?
p.s. I'm aware of a really hacky way, which is renaming friends attribute to friends[], but that's not solving my problem, as I have a lot of these and I can't go with redefining properties back and forth

From documentation:
non-GET "class" actions: Resource.action([parameters], postData, [success], [error])
So you have to use:
Person.save(null, $scope.person)
(first argument is object with url params, second is data to send)
Then your friends array will be available in request body.
Note also that if you have person resource, you can do:
var person = $resource(...);
person.name = 'john';
person.friends = ['friend1' ,'friend2'];
person.$save();

Related

Combine objects into new object as json for post for web api request

I am using Angular 4 with Typescript and ASP Core with C#. I am trying to combine objects together before calling a post to my web api. Currently I have two objects with values that I want to post as one object.
Let say I have two interfaces
export interface Student {
name: string;
}
export interface Teacher {
name: string;
}
And I wanted my json in my body of the post to look like this as my ASP Core is expecting this as a parameter to the web api request.
{
"StudentName": "John Doe",
"TeacherName": "Jane Doe"
}
I am using the following to create the json for the body but this puts it into two separate records in the json. This also does not allow me to select specific properties if my interfaces had more than what the request required.
const body = JSON.stringify({ student, teacher });
Next I tried to access only the specific member variables in the JSON.stringify method, but for some reason it does not work. In addition, if this even worked it would end up with two properties with the same name.
const body = JSON.stringify({ student.name, teacher.name });
I am not sure if this is a typescript, javascript or angular issue. I tried searching online for some help but I don't think I am using the right keywords.
Thanks in advance!
The problem is that you're not labeling your object items:
const body = JSON.stringify({ StudentName: student.name, TeacherName: teacher.name })
is the expected format.

How to handle model / API response translation in AngularJS?

I have an angular application that requests data from a JSON API. A sample API response might be:
{
id: 1,
name: 'JJ',
houseId: 2
}
In my angular application I will have models representing a User, which also has a reference to a House object:
{
id: 1,
firstName: 'JJ',
surname: '',
house: {
id: 2,
address: 'XXX'
}
}
The application model and API responses differ in that there is one field for the name in the API response, but two in my application model. Is there an 'angular' way I can do some transformation from an API call response object to my application model to ensure that I am always dealing with consistent objects in my controllers/services?
Related to this, the API responds with the database id of the house object associated with that user, and not with the full house object included in the JSON. Is there a way to set my object up to automatically resolve this when needed?
As an example, I would like to display this user, with his address. If the object was fully resolved I could use 'user.house.address'. However, using the plain JSON response object, this would be undefined. Instead of having to explicitly resolve the house object by using the house API with the houseId, I would like this to happen 'behind the scenes' by previously stating how such an id would be resolved if the object is accessed.
Or am I approaching this the wrong way and the API response should be used to dictate the data structure of my application and explicit lookups via object id's is the preferred way?

$promise stays promised on 'then' function

I'm using angular's $resource to perform a GET operation. This is how I do it:
var query = {customerid: $stateParams.customerid}
$resource('api/reports/running_count').get(query).$promise.then(function(value) {
$scope.runningInstance = value;
});
I also tried it like that:
$resource('api/reports/running_count').get(query, function(value) {
$scope.runningInstance = value;
});
The request returns a number. I checked the response with chrome's developer-tools. The request is indeed sent as follows:
<base-url>/api/reports/running_count?customerid=<id>
The response returns a number, again as expected.
But when I put a breakpoint in the callback function, the value is again a promise and not a number. Not sure what I'm doing wrong.
The $resource service doesn't work when the response is a primative. It uses angular.copy to copy the data to the $resource object and angular.copy doesn't copy a primative to an object. It can only make deep copies of properties of other objects.
From the Docs:1
angular.copy
Creates a deep copy of source, which should be an object or an array.
If a destination is provided, all of its elements (for arrays) or properties (for objects) are deleted and then all elements/properties from the source are copied to it.
If source is not an object or array (inc. null and undefined), source is returned.
In your case the source was not an object and you were getting just the $promise property which the $resource service attaches to the resource object.
From angular example https://docs.angularjs.org/api/ngResource/service/$resource:
var User = $resource('/user/:userId', {userId:'#id'});
User.get({userId:123}, function(user, getResponseHeaders){
user.abc = true;
user.$save(function(user, putResponseHeaders) {
//user => saved user object
//putResponseHeaders => $http header getter
});
});
Just put you values there.
As far I know if you want to get data using query value then server get query value as a string. it is useful when you will send query from search box . for example want to search product by name or something else then you can use like.
in service:
var query = {productname: '123'}
getProducts: function(query) {
var getProducts = $resource('/api/products', {}, {
'get': {method: 'GET', isArray: true}
});
return getProducts.get(query);
}
and server side will receive as req.query.productname so productname as a string so you need to convert it to number if needed as number.
but if you want to find produt by id you should send id as a parameter not query for exactly matching that also may send as string.
for example in service:
getProductById: function(id) {
var getProductById = $resource('/api/products/:id', {id: '#id'}, {
'get': {method: 'GET'}
});
return getProductById.get({id: id});
}
so server side will receive as req.params.id

opensocial newFetchPeopleRequest ignores parameters

I'm trying to get person info woth specifies fields:
var params = {};
params[opensocial.DataRequest.PeopleRequestFields.PROFILE_DETAILS] = [
opensocial.Person.Field.NICKNAME,
opensocial.Person.Field.PROFILE_URL,
opensocial.Person.Field.GENDER,
opensocial.Person.Field.THUMBNAIL_URL,
opensocial.Person.Field.ADDRESSES,
opensocial.Person.Field.DATE_OF_BIRTH
];
params[opensocial.IdSpec.Field.USER_ID] = ids;
var idSpec = opensocial.newIdSpec(params);
var req = opensocial.newDataRequest();
req.add(req.newFetchPeopleRequest(idSpec), "profiles");
But on responce, whatever person fields I'm setting up, I always get same set of fields in return:
displayName, id, isOwner, isViewer, nickname, thumbnailUrl
how to get requested fields?
UPD:
If this is important, social network I'm working with is yahoo mobage.
You are populating the params object but you are not actually using it in the request. You are merely using it in the opensocial.newIdSpec() call which gives you an IdSpec object. However, if you look at the documentation of the IdSpec object - this one has only user-related fields, additional data is ignored. You should actually pass in params in your newFetchPeopleRequest() call:
req.add(req.newFetchPeopleRequest(idSpec, params), "profiles");
For reference: opensocial.DataRequest.newFetchPeopleRequest method.

fetchRelated not fetching related

Been trying to get this up and running for a while now.
Basically i have a rest api as backend that returns json, all fine.
The problem i have is with backbone-relational. I'm sure i've just got something
wrong but i've been searching the nets for a while and couldn't find anything to help.
I'm trying to get a has many relationship between the model "Profession" and "Weapon".
Here's my code for that:
Profession = Backbone.RelationalModel.extend({
urlRoot: '../api/professions',
relations: [{
type: Backbone.HasMany,
key: 'weapons',
relatedModel: 'Weapon',
collectionType: 'Weapons',
reverseRelation: {
key: 'profession',
includeInJSON: 'id',
keySource: 'profession_id'
}
}]
});
Weapon = Backbone.RelationalModel.extend({
urlRoot: '../api/weapons'
});
Weapons = Backbone.Collection.extend({
model: Weapon,
url: function(models){
return '../api/weapons';
}
});
And a call to those api endpoints returns:
{name: "Profession1", id: 1}
[{name: "Weapon1", profession_id: 1}, {name: "Weapon2", profession_id: 1}]
So, if i understand correctly a profession.fetchRelated('weapons') should send an httprequest to the url for the weapons collection and pull the object which have a profession_id of 1. But nothing happens when i run profession.fetchRelated('weapons')
So, if i understand correctly a profession.fetchRelated('weapons') should send an httprequest to the url for the weapons collection and pull the object which have a profession_id of 1. But nothing happens when i run profession.fetchRelated('weapons')
This is not how I understand Backbone-relational to work - with the caveat that I'm working with an older version, and have not yet investigated the latest versions.
From my understanding, Backbone-relational wants data that looks different from your API responses.
I think that Backbone-relational wants references to nested models in the parent model response, either fully nested:
{
name: "Profession1",
id: 1,
weapons: [
{name: "Weapon1", profession_id: 1},
{name: "Weapon2", profession_id: 1}
]
}
In which case, it will fully populate the nested models.
Or, as references:
{
name: "Profession1",
id: 1,
weapons: ['weapon1','weapon2']
}
In which case Backbone-relational will stash the related keys internally, but present an empty collection. You would then use fetchRelated to fetch the full data for the related models:
assassin.fetchRelated('weapons')
Which make a request for weapons with id 'weapon1' and 'weapon2', either as individual requests, or if your API accepts a set request, a single request, expecting a response something like:
{id: 'weapon1', name: "Weapon1", profession_id: 1}
I don't, off the top of my head, know if there's a quick, built-in way to work with your API responses, other then to write a custom function.
To add to what Edward wrote, here's how you can get fetchRelated to work. First, as Edward claimed, fetchRelated will return nothing if your API already nests the data in the JSON response. So, if in Django-Tastypie you have your resource set up to use full=True:
movies = fields.ToManyField('movie.api.MovieResource', 'user', full=True)
then something like,
myuser.fetchRelated("movies")
will return nothing because the related data will already be included in the JSON response. But where fetch related is particularly useful is when you are attempting to do some lazy loading. So, if you have full=False in your Django-Tastypie field, and your JSON response only includes the id's and resource URI to that entry, you can use fetchRelated to actually populate that data.
myuser = new User({id: 1})
myuser.fetch()
myuser.fetchRelated("movies")
And now you have access to the related movies collection. If you're also using the Tastypie-Backbone plugin, you don't need to worry about constructing a special URL return statement in the Collection. It does it all for you using the tastypie select syntax of /2;3;7

Categories