Using jQuery's jsonp in a module
Coming up to speed on front end development with Javascript is getting to be more of a challenge than ever.
Recently I actively watched Wes Bos’s excellent free React/Redux tutorial (active means I typed in all the code along the way and made it run).
Then I created a demo of my own using a couple API’s to demonstrate using Promises to do async actions.
One of those API’s is freely available for anyone to use (https://www.googleapis.com/youtube/v3/search), and must have a CORS policy allowing this, as fetch
can be used to retrieve information asynchronously.
But the other (https://suggestqueries.google.com/complete/search?output=youtube&ds=yt&q=) is apparently mainly for Google’s internal use and does not have a CORS policy allowing the use of fetch
.
It does however support JSONP, a somewhat insecure way around the Same Origin Policy. So I decided to use JSONP for this.
There are many Javascript libraries for using JSONP, and I eventually used an npm module: ‘jsonp-es6’, but to get it working for the first time I fell back on jQuery. This code is
import store from '../store';
import { newSuggestions } from '../actions/actionCreators';
var BASE_URL='http://suggestqueries.google.com/complete/search?output=youtube&jsonp=datafn&ds=yt&q=';
var callback = function(data) {
var suggestions = data[1].map(elem => elem[0]);
console.log(" suggestions=");
console.log(suggestions);
store.dispatch(newSuggestions(suggestions));
}
function fetchSuggestions(text) {
$.getJSON("http://suggestqueries.google.com/complete/search?callback=?",
{
"hl": "en", // Language
"ds": "yt", // Restrict lookup to youtube
"jsonp": "callback", // jsonp callback function name
"q": text, // query term
"client": "youtube" // force youtube style response, i.e. jsonp
}
);
}
export default fetchSuggestions;
This code is in a webpack project module. When fetchSuggestions is invoked, the following error is produced in Chrome:
Uncaught ReferenceError: callback is not defined
.
Why does jQuery not bind jsonp to the local ‘callback’ function? Because jsonp can only be bound to a global variable, like this:
window.callback = function(data) {
This makes the callback variable global, so care must now be taken that it not collide with another global variable. If we use jsonp elsewhere we must pick a different name.
Replacing jQuery with the ‘jsonp-es6’ module eliminates all such worries:
import jsonp from 'jsonp-es6';
import store from '../store';
import { newSuggestions } from '../actions/actionCreators';
var BASE_URL='https://suggestqueries.google.com/complete/search?output=youtube&ds=yt&q=';
function fetchSuggestions(text) {
jsonp(BASE_URL + text)
.then((result) => {
var suggestions = result[1].map(elem => elem[0]);
//console.log(" suggestions=");
//console.log(suggestions);
store.dispatch(newSuggestions(suggestions));
});
}
export default fetchSuggestions;
jsonp now returns a promise, which when resolved invokes .then
. Much better.