There are a couple bits of extra info that would help us get right at the source of the issue. I think we can get by without them, but in case we get stuck, I would like to know:
- Are there any errors in the browser console?
- What does the search endpoint URL
appSettings.searchPath
look like?
- Does it contain colon-prefixed parameters?
- What kind of request is your endpoint expecting?
- Are you including jQuery or jQuery Lite, in addition to Angular?
Just to get things going, I'm going to assume you are not actually getting any console errors, and you've included the necessary libraries for both Angular and jQuery.
If that's the case, here are some tidbits that may help.
When you use the $request
factory, you produce a sort of interface that abstracts making HTTP requests. Since you're using this for "search", let's call this your search interface.
If you perform a GET request via your search interface's query
method, you can pass in any Object or Array and it will build a URL with a query based on that argument.
For example, let's say you passed in your newRequest
variable as-is, without any processing. That would end up producing a URL query like the following (decoded for readability):
?Facets={"Field":"createdBy","Value":"Joe"}&Facets={"Field":"createdBy","Value":"Mary"}&PageSize=25&SearchTerms=error
Notice how a Facets
parameter is specified twice? Once for each element in your Facets
array. This might actually work, if your end-point supports requests in that format.
On the other hand, using jQuery's $.param
utility, as you've attempted to do in this snippet from your first example...
{
query: {
method: 'GET',
transformRequest: function (data, headersGetter) {
if (data === undefined) {
return data;
}
return $.param(data);
}
}
... you would in theory end up with a URL query string like this (decoded for readability):
SearchTerms=error&PageSize=25&Facets[0][Field]=createdBy&Facets[0][Value]=Joe&Facets[1][Field]=createdBy&Facets[1][Value]=Mary
Why "in theory?" Well, as it turns out, you can't use $request
this way, for a few reasons.
'query' uses HTTP GET
Firstly, the HTTP method you specify for query
, will dictate what happens to the parameter object you pass in to that query
method.
Assuming query
uses HTTP GET (as in your examples), the parameter object will be serialized and appended to the end-point URL. You will end up with a URL that has something like this tacked onto it:
?Facets={"Field":"createdBy","Value":"Joe"}&Facets={"Field":"createdBy","Value":"Mary"}&PageSize=25&SearchTerms=error
By using HTTP GET, you are basically saying that the data you want to send with the request is embedded in the URL.
This happens regardless of any processing you specify in transformRequest
.
In fact, since this query
action is not an HTTP POST (it's a GET), there is no data to "post," because that's how GET works differently than POST (read up on HTTP methods, if this is new territory for you). That's why your transformRequest
function gets a data
argument that is undefined
.
What if we used HTTP POST?
Let's assume you set up query
to use HTTP POST. In that case, the parameter object you pass in when calling query
will be put in the post data (aka. request payload) of your HTTP request. It will not be appended to the URL, as had been done with GET.
By using HTTP POST, you are now declaring that the data you want to send can be found in the request body (not the URL).
Since there is "data" to post, the parameters object you pass into query
will be available as the data
argument in your transformRequest
function. This is good, because you can't just send in a raw object like newRequest
. You will need to serialize it into a string. Otherwise you'll end up with post data like:
[object Object]
But since this is now a POST, you don't have to format it like a URL query anymore (since it is not going onto the URL). You can use whatever data format your end-point wants to receive. If you're end-point accepts JSON, you could send a JSON encoded version of your newRequest
object, by running something like this in your transformRequest
function:
return JSON.stringify(data)
But what if we must use GET?
Sometimes you have no control over the end-point. What if it only takes GET requests for that search API you want to use? And what if it wants a very specific URL query format?
Not a problem... up to a point.
When you create your search interface via the $request
factory, you can specify a resource URL that is paramterized.
Let's say your search end-point URL was:
/search.do
And it want's to see GET requests with URLs like:
/search.do?PageSize=25&SearchTerms=error
You would then create your search interface with a paramaterized URL, something like this:
$resource("/search.do?PageSize=:PageSize&SearchTerms=:SearchTerms")
Such that you could pass in a request like:
searchResource.query({PageSize: 25, SearchTerms: "error"}, successCallback);
Which would make a GET request with a URL:
/search.do?PageSize=25&SearchTerms=error
Unfortunately this starts to break down with unbounded parameter lists like your Facets
array. The preceding pattern requires that you have a fixed list of arguments.
Let's not forget that if your end-point is not too picky, then you could always just send a GET request with a URL serialized like this:
?Facets={"Field":"createdBy","Value":"Joe"}&Facets={"Field":"createdBy","Value":"Mary"}&PageSize=25&SearchTerms=error
which is what $resource
does to your newRequest
object for free.
Let's get complicated
What if your really, REALLY want to use $request
, and you have to send GET requests that look like the output of $.param
?
Okay. Let's get fancy. JS fancy.
If you are only ever going to use the query
method on your search interface, you can just wrap the object produced by $resource
.
.factory("searchResource", ["$resource", searchResource]);
function searchResource($resource) {
var searchDelegate = $resource("/search.do?:queryString");
var searchInterface = {
query: function (params) {
var encodedQuery = $.param(params);
return searchDelegate.query({queryString: encodedQuery});
}
};
return searchInterface;
}
Now you can pass in your newRequest
object as-is, and your wrapped search resource will make a GET request to this URL (decoded for readability):
search.do?SearchTerms=error&PageSize=25&Facets[0][Field]=createdBy&Facets[0][Value]=Joe&Facets[1][Field]=createdBy&Facets[1][Value]=Mary
$resource
, this is a good read: blog.mgechev.com/2014/02/05/… – Kairouan