How to properly send URL parameters containing commas using AngularJS? - javascript

I have a feeling I am just looking at this wrong, but I want to get feedback on the proper way to pass URL query parameters through Angular's $http.get() method - specifically, parameters that contain commas.
Let's say I have the following data, to be used as URL parameters in a GET request:
var params = {
filter : [
"My filter",
"My other filter",
"A filter, that contains, some commas"
],
sort : [
"ascending"
]
};
Now, I convert this structure to some parameters that can be fed into $http.get:
var urlParams = {};
angular.forEach(params, function(value, name) {
urlParams[name] = "";
for (var i = 0; i < value.length; i++) {
urlParams[name] += value[i];
if (i < value.length - 1) {
urlParams[name] += ","
}
}
}
At this point, urlParams looks like this:
{
filter : "My filter,My other filter,A filter, that contains, some commas",
sort : "ascending"
}
Now, that isn't what I want, since the third filter parameter has now turned into three separate parameters. (The API I am working with does not allow multiple values for a parameter to be passed in any other way than: "?param=value1,value2,value3") So, what I need to do is URI encode these values first, right? So, I add a encodeURIComponent() to the above routine like this:
urlParams[name] += encodeURIComponent(value[i]);
This gives me a parameters object that looks like this:
{
filter : "My%20filter,My%20other%20filter,A%20filter%2C%20that%20contains%2C%20some%20commas",
sort : "ascending"
}
Now, I make a request:
var config = {
params : urlParams
};
$http.get("/foo", config).then(function(response){
console.log(response);
});
... and this doesn't work, since Angular encodes the URL parameters as well, so the request ends up looking like this:
GET "/foo?filter=My%2520filter,My%2520other%2520filter,A%2520filter%2C%20that%20contains%2C%20some%20commas&sort=ascending"
As you can see the parameters are being encoded twice (the % signs are being encoded as %25), which of course, won't work.
Obviously, I am doing it wrong. But what is the right way? Or, do I need to ask the API developer to accept URL parameters like this?
GET "/foo?filter=My+filter,+with+a+comma&filter=Another+filter"
where multiple parameter values are stated separately, instead of being comma delimited?

As you've described the API, there is no way to reliably pass values containing commas.
Suppose you want to pass the items ["one","two","three,four"] as a list.
If you pass the strings as-is, the API will see (after the normal server-side URL decoding)
one,two,three,four
which makes the three,four indistinguishable from two separate items.
If you pass the strings URL-encoded, the entire parameter will be double-encoded, and the API will see (again, after URL decoding)
one,two,three%2Cfour
Now the parameters are distinguishable, but this requires support from the API to URL-decode each item separately.
Suppose you pass the strings like one,two,"three,four", i.e. items containing commas are quoted. The API can decode the parameters correctly, but it needs to support a more complex syntax (quoted strings) instead of simply splitting by commas...
...and so on. The bottom line is that without additional support from the API, I don't think there is anything you can do client-side to trick it into decoding strings containing commas correctly. There are many tweaks that the API developer can make, e.g.
Accepting some escape sequence for commas within list items which is unescaped server-side.
Accepting each item in a separate URL parameter.
Accepting JSON-encoded body via POST.
You will need to ask the API developer to do something.

I think you shouldn't have used comma as delimiter of the array.
I would recommend to
send json data using POST (which requires API change)
or use another string as delimiter. For example, ###.
FYI, you can simply join your array into string like this.
array.join(',')

From $http docs
If you wish override the request/response transformations only for a single request then provide transformRequest and/or transformResponse properties on the configuration object passed into $http.
Note that if you provide these properties on the config object the default transformations will be overwritten. If you wish to augment the default transformations then you must include them in your local transformation array.
In short you can use your encodeURIComponent() functionality to replace the default one by including transformRequest property in the config object for each request or you can establish a global override
See "Transforming Requests and Responses" in $http docs for more details
Not sure why you want to send this as GET in the first place

Related

How to add parameters to a api?

I am trying to study wordpress REST api
If I do:
https://www.example.com/wp-json/wp/v2/categories
I get all categories.
But let's say I want to exclude a category, according to the documentation it says:
exclude
Ensure result set excludes specific IDs.
So I try
https://www.example.com/wp-json/wp/v2/categories?exclude=697
I still get all categories, am I using wrongly the parameters?
Should it be written like
https://www.example.com/wp-json/wp/v2/categories/exclude=697
or
https://www.example.com/wp-json/wp/v2/categories&exclude=697
Here it is the doc
The right way is
http://demo.wp-api.org/wp-json/wp/v2/categories?exclude=2,11
It's the ids separated by comma. I get the categories filtered. Category 697 doesn't seem to exist in the API example.
When you do a GET request, you send the parameters in the Query String. After the url, you end it with ? and the assign the value of the parameter like this: name_of_the_parameter=something. If you have multiple parameters, you concatenate them with &, For example:
http://example.com/some/page?name=ferret&color=purple

How can I remove dynamic data in string before a value in that string? / using Lodash's _.trimStart with dynamic data?

I'm working urls returned from a server that I have no control over where and sometimes the urls return with extra data at the front.
For instance
sometimes it returns this
https://example.com/image/5119b3905.jpg
and this I can use, but sometimes it will return something like this
https://d1yww.cloudfront.net/9MA=/670x670/example.com/image/5119b3905.jpg
where I'd like to use remove everything before the example.com and to do that I could use something like lodash's _.trimStart method something like
_.trimStart('https://d1yww.cloudfront.net/9MA=/670x670/example.com/image/5119b3905.jpg',
'd1yww.cloudfront.net/9MA=/670x670');
but the d1yww.cloudfront.net/9MA=/670x670' is never static for me to do this and I don't know how to grab the dynamic data to use _.trimStart and I don't see any other useful lodash's methods and I don't know of any vanilla javascript ones.
TLDR: How can I remove dynamic data in string before a value in that string (in this example everything before the example.com)
You don't need lodash to do that
var str = 'https://d1yww.cloudfront.net/9MA=/670x670/example.com/image/5119b3905.jpg'
str.substr(str.indexOf('example.com'))
You could search for a Regular Expression
For Example:
/\/([-a-zA-Z0-9#:%._\+~#=]{2,256}\.[a-z]{2,6}\b)\//g
and look for the second match

converting Google Visualization Query result into javascript array

The url to the spreadsheet I am querying is
docs.google.com/spreadsheets/d/1EIBhBQY1zbdBEKXsJIY1uyvdQw0b1cIBSrBE_tZvA6Y/edit?usp=sharing
The query url being used is
https://spreadsheets.google.com/tq?tqx=out:&key=1EIBhBQY1zbdBEKXsJIY1uyvdQw0b1cIBSrBE_tZvA6Y&gid=0&headers=1&tq=select%20B%2CC%2CD%20where%20(A%20matches%20%22DIS%22)
Is there a way to convert or store this result in a JavaScript array?
var dis = ["The Walt Disney Company","Entertainment",.1]
I need to be able to manipulate the data at one point and add the new data to the visualization.
Data from one of multiple queries --> Convert to array --> Manipulate data ex: multiplying an input --> data.addRows(manipulated input);
Your query does return a string containing JSON wrapped in a function call:
var responseText = 'google.visualization.Query.setResponse({…});';
This is because you specified out: as an argument for tqx (see Google Developers guides).
If you want it all raw, you can extract and parse the JSON of multiple queries and push the data to an array, so you end up with an array of arrays of row data. For your single query, you could start from something like this:
responseJSON = JSON.parse(
responseText.replace(/(^google\.visualization\.Query\.setResponse\(|\);$)/g,'')
);
var rowsArray = [];
responseJSON.table.rows.forEach(function(row){
var rowArray = [];
row.c.forEach(function(prop){ rowArray.push(prop.v); });
rowsArray.push(rowArray);
});
console.log(rowsArray); // === [["The Walt Disney Company", "Entertainment", 0.1]]
There is a more straightforward solution to this. What you get in the response is a JSONP string whose data is hold within a callback function, just as #dakab has mentioned.
Besides this, recently Google has included some extra text in the response to help with some anti-content-sniffing protections to their API. You can read more about this in this Github thread. The response you get now is an unparseable string in this form:
/*O_o*/
google.visualization.Query.setResponse({…});
One way to deal with both issues (the "comment" string and the data hidden inside the callback function) is to evaluate the function. Whether this is risky or not is something intrinsic to the JSONP format, so you must be aware of where your response comes from and decide if it's worth the risk. But, considering it comes from a request to a Google server, and in terms of parsing, it works.
So in your case, what you could do is just declare the callback function (note that you can pass your own function name in the query string, as also mentioned in the Google Developers guides) and then evaluate it. I take inspiration on this thread:
//Declare your call back function
function callback(data){
return data;
}
//Evaluate and store the data in your callback function
var result = eval(UrlFetchApp.fetch(url + uri, options).getContentText());
In "result" you'll have an already parsed JSON that you can convert to whatever you wish.
According to Google's documentation on their Visualization API for response formats, you can add a header in your request that will return JSON without the function or comment.
If you add a header named X-DataSource-Auth in your request, the Visualization API will respond in JSON format rather than JSONP format, which is the default format of the response and includes the JSON wrapped in a function handler.
However, even with this header present, the API prepends a strange string to the response: )]}' which I think has to do with the anti-content-sniffing mentioned by #Diego. Okay, Google — even with an OAuth token do you really need to do that?
So, to get at the actual JSON in that response, you can use the following Javascript to get around it. Assume responseBody is what the API actually returns to you, and that data is storing the JSON you want.
var data = JSON.parse(responseBody.replace(/^\)]\}'\n/, ''));
Assuming str is the returned JSONP formatted response:
var str = `/*O_o*/
google.visualization.Query.setResponse({"version":"0.6","reqId":"0","status":"ok","sig":"403123069","table":{"cols":[{"id":"A","label":"Timestamp","type":"datetime","pattern":"dd/MM/yyyy HH:mm:ss"},{"id":"B","label":"AskGod Search Query","type":"string"}],"rows":[{"c":[{"v":"Date(2020,9,25,12,30,5)","f":"25/10/2020 12:30:05"},{"v":"لا أعرف لماذا"}]}],"parsedNumHeaders":1}});`
console.log(JSON.parse(str.match(/(?<=.*\().*(?=\);)/s)[0]))

Ruby & Rails - Convert String to Proc

I'm in the following situation. The current url looks like the following:
/categories/Art
And I'm using name = location.pathname.split('/')[2] in order to grab the Art portion of the URL. Then, I send an AJAX the following path back to the controller: http://localhost:3000/sort?sortMethod=name&category=name or date, whichever link is clicked on.
Now in my controller I can use sort = params[:category] to get the string name, yet what I'd like to do with this string is sort an array by it. #categories is an array of objects and I'd like to call .sort_by(&:sort) yet it doesn't recognize the string value of sort = name. So now I'd like to convert this string into a proc in order to sort the array. Anyone know how I accomplish this?
Any help is greatly appreciated!
Convert it to a symbol first and then use Symbol#to_proc:
#categories.sort_by(&sort.to_sym)
However be sure that the users can't call anything malicious on your objects like:
http://localhost:3000/sort?sortMethod=destroy
One way of protecting yourself is to use attribute_accessible definitions in your model and then do
#categories.sort_by(&sort.to_sym) if Category.accessible_attributes.include? sort.to_sym
The problem is not entirely clear, so you may need to adjust the following solution. However, the basic idea is taht it's possible to do something like:
Category.all.sort_by {|category| category.method(params[:category]).call }
Also, the "Art" portion of your url is available in Rails' params hash as params[:action], so you don't have to do location.pathname.split('/')[2].

How do I remove the square brackets at the end of a JS variable name during AJAX calls?

I currently have the following javascript array:
var stuffs = ['a', 'b'];
I pass the above to the server code using jQuery's load:
var data = {
'stuffs': stuffs
};
$(".output").load("/my-server-code/", data, function() {
});
On the server side, if I print the content of request.POST(I'm currently using Django), I get:
'stuffs[]': [u'a', u'b']
Notice the [] at the prefix of the variable name stuffs. Is there a way to remove that [] before it reaches the server code?
This is default behavior in jQuery 1.4+...if you want the post to be &stuffs=a&stuffs=b instead of &stuffs[]=a&stuffs[]=b you should set the traditional option to true, like this:
$.ajaxSetup({traditional: true});
Note this affects all requests... which is usually what you want in this case. If you want it to be per-request you should use the longer $.ajax() call and set traditional: true there. You can find more info about traditional in the $.param() documentation.
When an array is submitted using a GET request, through a form or AJAX, each element is given the name of the array, followed by a pair of optionally empty square brackets. So the jQuery is generating the url http://example.com/get.php?stuff[]=a&stuff[]=b. This is the only way of submitting an array, and the javascript is following the standard.
POST requests work in exactly the same way (unless the json is sent as one long json string).
In PHP, this is parsed back into the original array, so although the query string can be a little strange, the data is recieved as it was sent. $_GET['stuff'][0] works correctly in PHP.
I'm not sure how Django parses query strings.
The [] indicates that the variable is an array. I imagine that the appending of the [] to your variable name is Python/Django's way of telling you it is an array. You could probably implement your own print function which does not show them.

Categories