AngularJS + Parse API call service not constrained by userId as intended - javascript

For my app, I've created a service for Address, which allows me to manipulate Address objects for any given user. Aside from my standard CRUD functions, I need to have one function to list any address for a specified Parse.User.
services.js
.factory('Address',['$http', 'PARSE_CREDENTIALS', function ($http,PARSE_CREDENTIALS) {
return {
// constrain to User ID
getAll: function(userId) {
return $http.get('https://api.parse.com/1/classes/Address', {
headers: {
'X-Parse-Application-Id': PARSE_CREDENTIALS.APP_ID,
'X-Parse-REST-API-Key': PARSE_CREDENTIALS.REST_API_KEY,
'Content-Type' : 'application/json'
},
params: { "userId": userId }
});
},
// ...get(), edit(), add(), delete()
controllers.js
.controller('AddrCtrl', ['$scope', '$state', '$stateParams', '$rootScope', 'Address',
function($scope, $state, $stateParams, $rootScope, Address) {
Address.getAll($rootScope.user.id)
.success( function(data) {
console.log(data);
$scope.addresses = data.results;
})
}]);
In my Angular template, the view does return Address objects. But it returns all the Address objects when it should only be returning the Address objects with a corresponding userId. To clarify, the Address class has a userId pointer column. Each address only has one User.
Here is the log message that AddrCtrl returns in the console:
Object {results: Array[2]}
results: Array[2]
0: Object
firstName: "(test)"
lastName: "test"
// more unrelated properties
objectId: "yUEuFjLlzs"
updatedAt: "2014-12-02T20:17:55.608Z"
userId: Object
__type: "Pointer"
className: "_User"
objectId: "q1KADkp4i1"
I'm assuming that the issue lies somewhere in my $http.get() function. Ultimately, my questions is this: why does my params option not constrain my data.results to just the Address objects associated with one Parse.User?
Answer I am not looking for:
Return all Address objects and only save the ones matching Parse.User.current().id into $scope.

You need to use where clause to perform the query.
If the data type of userId is Pointer, you should write as following:
{"where": JSON.stringify({
"userId": {"__type":"Pointer","className":"_User","objectId":"userId"}}
)}

Related

Angular $http - How to access JSON result values

I have a $http request which returns an object of a user.
$scope.profile = $http.get('api/users/' + $stateParams.userId).success(function(data) {
console.log(data);
});
How do i actually assign for example a user.username to $scope.profileUsername?
Copied from the console...
Object
__v: 0
_id: "56a1832a36dc3d0e00c7aa3f"
aboutme: "<p>Im the Boss.</p>"
additionalProvidersData: Object
county: "waterford"
created: "2016-01-22T01:17:30.863Z"
displayName: "Chris"
firstName: "Chris"
gender: "male"
imageURL: "/modules/users/client/img/profile/saveme-placeholder.png"
profileImageURL: "../modules/users/client/img/profile/avatars/2/45.png"
provider: "local"
roles: Array[2]
updated: "2016-02-09T02:55:38.744Z"
username: "abcdef"
__proto__: Object
Try this.
$http.get('api/users/' + $stateParams.userId).success(function(data) {
$scope.profileUsername = data.username;
});
The return values of the $http methods are promises, not the data.
This is due to their asynchronous nature and the function you pass as a callback is only executed once the HTTP requests returns, so do anything you want to do with the data, you gotta do it in the callback function.
EDIT:
You could also do it like this
$http.get('api/users/' + $stateParams.userId).success(function(data) {
$scope.profile = data;
});
That way you can have all the data in one variable, assuming you need all of it.
In your templates you can then just access the properties with the dot notation (profile.username).
Should be
$http.get('api/users/' + $stateParams.userId).success(function(data) {
$scope.profile=data;
});
It should be accessible on views like {{profile.username}}

AngularJS routing, pass id with ui-sref while displaying a slug and not the id in the url

I'll outline what I've set up and what I'd like to work:
I have a list of items in my template like this:
<ul>
<li ng-repeat="user in users">
<a ui-sref="user({slug: user.slug, id: user.id})">
{{user.name}}
</a>
</li>
</ul>
I have a state provider looking like this:
.state('user', {
url: '/:slug',
controller: 'UserCtrl',
templateUrl: 'app/user/userProfile.html',
resolve: {
user: function($stateParams, UserService) {
return UserService.get($stateParams.id);
}
}
});
Now I understand that this isn't working because the id parameter is not defined in the url and so it isn't passed to the $stateParams. I have seen similar questions answered with suggestions of using something like this:
resolve: {
user: function($stateParams, UserService) {
var userId = UserService.getIdFromSlug($stateParams.slug);
return UserService.get(userId);
}
}
But the getIdFromSlug method is either going to require another API call or when I get the list, creating a mapping object in the service like { slug: id }. Both don't seem like very elegant solutions, especially since I already have the id.
Am I missing something? Is there no other way to pass parameters through to the state provider? (I am fairly new to Angular).
.state('user', {
url: '/:slug',
params: { id: { value: -1 } },
I have used the above so the ids where not passed in the url.
You can pass both slug and id , but than you have to code both in the url
url: '/:slug/:id'
like this you can pass both
You can add id in the url like
url: '/:slug/:id'
Or treat it as the query string like below
url: '/:slug&id

AngularJS $resource passes id as query parameter instead in url

I need to GET data from a rest API, with the product id part of the url (and not as query parameter).
The factory:
.factory('Products', ['$resource',
function($resource) {
return $resource('products/:productId', {
productId: '#id'
}, {
query: {
isArray: false
},
update: {
method: 'PUT'
}
});
}
])
The controller:
$scope.getProduct = function(id, from) {
$scope.product = Products.get({ id: id }, function(){
console.log($scope.product);
});
}
My url is constructed like:
/products?id=5426ced88b49d2e402402205
instead of:
/products/5426ced88b49d2e402402205
Any ideas why?
When you call Products.get() in the controller, you are not using the correct parameter name (you need to use "productId" instead of "id" based on your definition of the $resource). Try calling it like this instead:
Products.get({ productId: id })
Here is a snippet from the documentation for $resource which explains how it works:
Each key value in the parameter object is first bound to url template if present and then any excess keys are appended to the url search query after the ?.
In your case, it's not finding "id" as a parameter in the URL, so it adds that to the query string.

Sending 2 objects in 1 POST request

I'm using Angular and trying to send a request (using $resource) to an external API but I have the data I need to send in 2 different objects, while I currently only send 1. The API requires user specific actions to include an auth_token with every request.
Without the auth_token, the request would look like this:
APIShop.reg(Cart.data,
function(success) {},
function(failure) {}
);
APIShop looks like this:
app.provider('APIShop', function(API_URL) {
this.$get = ['$resource', function($resource) {
var Campaign = $resource(API_URL.url + API_URL.loc + ':service/:action/', {service: '#service', action: '#action'}, {
'reg': {method:'POST', isArray: false, params: {service: 'account', action: 'order'}},
'update': {method:'PUT', isArray: false, params: {service: 'account', action: 'order'}}
});
return Campaign;
}];
});
Cart.data is an object that looks like: {country: 'US', city: 'Seattle, WA'}
but I need to also add {auth_token: '432078e36c7a42e3c6febdac95f38c1549de6218'} from the User object in the same request. The immediate solution would probably be to add the auth_token field to the Cart object, but as I'm storing this data in the application in various models User, ShoppingCart, etc, I'd like to keep auth_token in the User object.
I tried doing
APIShop.reg(Cart.data, User.auth_token
function(success) {},
function(failure) {}
);
didn't expect it to work, and it didn't. The auth_token ends up showing as a Request Payload instead of Query String Parameters.
I also don't want to send something like {country: Cart.data.country, city: Cart.data.city, auth_token: '432078e36c7a42e3c6febdac95f38c1549de6218'} directly (as opposed to sending the object) as that will become a maintenance nightmare sooner or later.
How would I go about sending both pieces of information without adding the token to Cart (since it'll mean I need to add it to every object going forward), or listing all the fields of the object?
Refactor APIShop to receive an array:
APIShop.reg([Cart.data, User.auth_token],
function(success) {},
function(failure) {}
);
Or refactor it to receive a mapping object:
APIShop.reg({ data : Cart.data, auth : User.auth_token },
function(success) {},
function(failure) {}
);

Angularjs resource query() result array as a property

I like the way the query() method returns an array of resources, which can be saved to the server again.
I am trying to use Angular against the Drupal RestWS module, which returns an object with several "meta" properties and a property called list where the actual data are stored. Is there please a way of telling the resource to take that array instead ?
Example : GET author.json returns :
first: "http://dgh/author?page=0"
last: "http://dgh/author?page=0"
list: [{id:1, type:author, uid:{uri:http://dgh/user/1, id:1, resource:user}, created:1367770006,…},…]
self: "http://dgh/author"
With the latest Angular version (1.1.2 or later), you can configure the resource with a transformResponse:
var MyResource = $resource(
'/author.js',
{},
{
'get': {
method: 'GET',
transformResponse: function (data) {return angular.fromJson(data).list},
isArray: true //since your list property is an array
}
}
);

Categories