Angularjs resource query() result array as a property - javascript

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
}
}
);

Related

Uncaught TypeError: b.toLowerCase is not a function

I am fetching some records :
$companies = \App\User::where('type', 'pet-salon')->orWhere('type', 'veterinarian')->get();
return response()->json($companies);
The data coming back is an array of objects:
[{
id: 2,
type: "xxx",
deactivate: 0,
xxx: "Hello",
middle_name: "Mid",
lastname: "xxx",
//...
}]
This is the jQuery typeahead code:
$('#getCompaniesForConnection').typeahead({
source: function (query, process) {
return $.get('/all/companies', { query: query }, function (data) {
return process(data);
});
}
});
The exception its giving me :
Uncaught TypeError: b.toLowerCase is not a function
And the results drop-down is not showing too, What am i missing here ?
Yes, you need to json_encode your companies.
$companies = \App\User::where('type', 'pet-salon')->orWhere('type',
'veterinarian')->get();
$result = json_encode($companies ); // return this or echo
First, the PHP code looks like it's a laravel code, so you can just return the $companies variable like so:
$companies = \App\User::where('type', 'pet-salon')->orWhere('type', 'veterinarian')->get();
return $companies;
Since models and collections are converted to JSON when cast to a string, you can return Eloquent objects directly from your application's routes or controllers.
And also, let's see the definition of the process function to be sure that's not where the error is coming from.

ASP.NET MVC Action Not Getting Parameter Values

I am working on an ASP.NET MVC 4 app. This app has a controller with an action that looks like the following:
public class MyController : System.Web.Http.ApiController
{
[ResponseType(typeof(IEnumerable<MyItem>))]
public IHttpActionResult Get(string id, string filter)
{
IEnumerable<MyItem> results = MyItem.GetAll();
List<MyItem> temp = results.ToList<MyItem>();
var filtered = temp.Where(r => r.Name.Contains(filter);
return Ok(filtered);
}
}
I am calling this action using the following JavaScript, which relies on the Select2 library:
$('#mySelect').select2({
placeholder: 'Search here',
minimumInputLength: 2,
ajax: {
url: '/api/my',
dataType: 'json',
quietMillis: 150,
data: function (term, page) {
return {
id: '123',
filter: term
};
},
results: function (data, page) {
return { results: data };
}
}
});
This code successfully reaches the controller action. However, when I look at id and filter in the watch window, I see the following errors:
The name 'id' does not exist in the current context
The name 'filter' does not exist in the current context
What am I doing wrong? How do I call the MVC action from my JavaScript?
Thanks!
You're not passing actual data as the parameters, you're passing a function:
data: function (term, page) {
return {
id: '123',
filter: term
};
}
Unless something invokes that function, the result will never be evaluated. Generally one would just pass data by itself:
data: {
id: '123',
filter: term
}
If, however, in your code there's a particular reason (not shown in the example) to use a function, you'll want to evaluate that function in order for the resulting value to be set as the data:
data: (function (term, page) {
return {
id: '123',
filter: term
};
})()
However, these errors also imply a second problem, probably related to however you're trying to debug this:
The name 'id' does not exist in the current context
The name 'filter' does not exist in the current context
Even if no values were being passed, id and filter still exist in the scope of the action method. They may be null or empty strings, but the variables exist. It's not clear where you're seeing that error, but it's definitely not in the scope of the action method.

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, $http and transformResponse

I'm getting a strange behaviour with AngularJS's $http and not really understanding how transformResponse works (the docs are a bit light on this one).
WebAssets.get = function () {
return $http.get('/api/webassets/list', {
transformResponse: [function (data, headersGetter) {
// not sure what to do here?!
return data;
}].concat($http.defaults.transformResponse) // presume this isn't needed, added for clarity
}).then(function (response) {
return new WebAssets(response.data);
});
};
The api returns an array of objects:
[{"webasset_name": "...", "application_id": "...", "etc": "..."}, ... ]
But when transformResponse has done it's evil business the data has transformed into an indexed object:
{"0":{"webasset_name":"...","application_id":"...", "etc": "..."}, "1":....}
I want to keep the original data structure (an array of objects).
To get angular to not convert your data into an object you need to override the behavior of the default $httpProvider.defaults.transformResponse. It is actually an array of transformers.
You could just set it to be empty: $http.defaults.transformResponse = [];
Here is an example transformer I have used to convert 64-bit long ints to strings:
function longsToStrings(response) {
//console.log("transforming response");
var numbers = /("[^"]*":\s*)(\d{15,})([,}])/g;
var newResponse = response.replace(numbers, "$1\"$2\"$3");
return newResponse;
}
To add a transformer to the default list, say ahead of the JSON deserializer, you can do this:
$http.defaults.transformResponse.unshift(longsToStrings);
Resource 0: "f" 1: "a" 2: "l" 3: "s" 4: "e"
This finally worked for me:
transformResponse: function (data, headersGetter) {
return { isCorrect: angular.fromJson(data) }
}
Try using resource query method
https://github.com/angular/angular.js/issues/6314

Categories