I'm making multiple mapping API calls using the value of the input field (which is a postcode) and passing this as an argument for the API URL. I am also saving the postcode to localStorage to use for displaying purposes elsewhere.
When I set var userPostalCode = $('#input').val() as a global variable, nothing seems to work. I've even placed an event.preventDefault() on my click handler function to try to circumvent this. However, when I set the variable scoped to the function, it works. The issue here is, this isn't DRY whatsoever as I have to repeat the same line for each API call.
How can I a) make this DRY and b) can you please explain why I can't have it as a global variable? Abstracted code below for context:
// Fires call to all API functions and renders page
myBtn.click(function(event) {
event.preventDefault();
// Runs mapping functions
firstAPICall();
secondAPICall()
saveToLocalStorage()
});
function firstAPICall() {
var userPostalCode = $('#input').val();
var FIRST_URL = `https://anotherwebsite.com/query=${userPostalCode}&limit=6&api_key=${API_KEY}`;
$.ajax({
url: FIRST_URL,
method: "GET"
}).then(function(response) {
// Code block
});
};
function secondAPICall() {
var userPostalCode = $('#input').val();
var SECOND_URL = `https://somewebsite.com/location=${userPostalCode}&api_key=${API_KEY}`;
$.ajax({
url: SECOND_URL,
method: "GET"
}).then(function(response) {
// Code block
});
};
function saveToLocalStorage() {
var userPostalCode = $('#input').val();
savedSearches.push(userPostalCode);
localStorage.setItem("zipCode", JSON.stringify(savedSearches));
};
To get DRY code, get the value in the click handler and pass it as a parameter.
// Fires call to all API functions and renders page
myBtn.click(function(event) {
event.preventDefault();
let userPostalCode = $('#input').val();
// Runs mapping functions
firstAPICall(userPostalCode);
secondAPICall(userPostalCode)
saveToLocalStorage(userPostalCode)
});
function firstAPICall(userPostalCode) {
var FIRST_URL = `https://anotherwebsite.com/query=${userPostalCode}&limit=6&api_key=${API_KEY}`;
$.ajax({
url: FIRST_URL,
method: "GET"
}).then(function(response) {
// Code block
});
};
function secondAPICall(userPostalCode) {
var SECOND_URL = `https://somewebsite.com/location=${userPostalCode}&api_key=${API_KEY}`;
$.ajax({
url: SECOND_URL,
method: "GET"
}).then(function(response) {
// Code block
});
};
function saveToLocalStorage(userPostalCode) {
savedSearches.push(userPostalCode);
localStorage.setItem("zipCode", JSON.stringify(savedSearches));
};
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
Created a fiddle for this as it is so simple but yet it doesn't work;
var url = 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json';
function getData (url) {
return $.ajax({
'type': "POST",
'url': url
});
};
$(document).ready(function(){
var a = null;
getData(url).done(function(data){ a = data; });
alert(a);
});
early morning perhaps?
Fiddle: https://jsfiddle.net/nextgenmappinginc/r88356tu/
Goal:
I have multiple local files which contain geojson data. Which I will be returned to me as an array. I want to loop through these create objects and push these objects into an array. Then from the new array created by all of these ajax calls. I want to pass this array to a function that will execute open layers code.
updated and completed different fiddle
https://jsfiddle.net/nextgenmappinginc/x1yasngy/
But. Problem remains. Even when you pass through ASYNC The function is only fired upon request. Then it remains in the function. So technically why can't it pass it to another function that can then console it?
In the fiddle you can simply change the urls so that you can get request response
//var url = 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json';
var url = {url : 'clientData/10BC99F2-05FD-4847-A277-2979C83BB42A/geojson/E36CC45E-C1B8-4C26-A714-EBA91ACE7C1C.js'}
var files = [];
files.push(url);
function getData (files) {
var fileObjects = [];
for (i=0; i<files.length; i++){
$.ajax({
'type': "GET",
'url': files[i].url,
success: function (response){
fileObjects.push(response);
}
});
}
consoleMe(fileObjects);
}
function consoleMe(data){
console.log(data);
}
getData(files);
add async:false, in your ajax code. Remove this line
getData(url).done(function(data){ a = data; });
and add below line
getData(url).done(function(data){ a = data; });
Try below example this will work for sure
var url = 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json';
function getData (url) {
return $.ajax({
'type': "POST",
async:false,
'url': url
});
};
$(document).ready(function(){
var a = null;
a = getData(url);
console.log(a);
alert(a);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
You want to "get" data but you do a post request to the API. Secondly .done is an asynchronous function. It will be execute when the API sends you the data.
Code
var url = 'https://api.tiles.mapbox.com/v3/mapbox.geography-class.json';
function getData (url) {
return $.ajax({
'type': "get",
'url': url
});
};
$(document).ready(function(){
getData(url).done(function(data){
// here you have access to data
alert(data)
});
});
I'm trying to pass a parameter from a onload GET method call to a POST method. The GET method is being loaded on window.onload and the POST function is not in the onload call otherwise the POST function will trigger once the window has loaded. I only want to trigger POST function when I click a button.
How can I pass a variable from a onload AJAX call to my POST function?
The only way I could think of is using a global variable however I don't think that's a good way of passing it to another function.
window.onload = function () {
function firstCallBack() {
$.get('http://website.com/API/docs/v1').then(function(data1){
var passThis = "PassMeToPOST"
}).then(function (data2) {
})
}
}
POST function
function saveSettings(passThatVar) {
var urlVal = window.__env.url+ "Preview/TypeDefinition";
var xslSettingVal = $('#PreviewXml').val().replace(/\n/g, "");
var allData = {
'ObjectName': passThatVar,
'DisplayDefinition': setting,
}
$.ajax({
url: urlVal,
type: "POST",
data: JSON.stringify(allData),
success: function (data) {
console.log('success');
}
});
}
Button HTML:
<button onclick="saveSetting()"> Save Setting </button>
Try this:
Your button:
<button id="save-settings"> Save Setting </button>
After your get request, set a data-attribute to your button:
function firstCallBack() {
$.get('http://website.com/API/docs/v1').then(function(data1){
$("#save-settings").data("passMe", "PassMeToPOST");
}).then(function (data2) {
})
}
Bind the click event(its a best practice than using inline events):
$("#save-settings").on("click", saveSetting);
On your saveSetting() function:
function saveSetting() {
var allData = {
'ObjectName': $(this).data("passMe"),
'DisplayDefinition': setting,
}
//... your post request
}
You can also check if the get request has finished before starting the post request(to avoid a bug in an extreme scenario):
if (!$(this).data("passMe")) {
return;
}
You're basically asking how to keep a variable out of the global scope. This is called encapsulation. It is a good instinct but a large topic. Here is a post that I like on the topic: http://javascriptissexy.com/oop-in-javascript-what-you-need-to-know/
One low budget way of doing this is instead of making a global variable for your value, make a global namespace for your own use.
var MyUniquelyNamedThing = {};
...
// get response:
MyUniquelyNamedThing.ThatValueINeed = data;
...
// posting:
data = { val1: MyUniquelyNamedThing.ThatValueINeed , etc. };
I'm writing something to get all the layers names from my GeoServer. This is my code:
function getData() {
return $.ajax({
url: "http://localhost:8080/geoserver/ows?service=wms&version=1.1.0&request=GetCapabilities",
type: 'GET'
});
}
function onComplete(data) {
var parser = new ol.format.WMSCapabilities();
var result = parser.read(data.responseText);
var layersArray = result.Capability.Layer.Layer;
layersNameArray = [];
for(i=0;i<layersArray.length;i++){
layersNameArray.push(layersArray[i].Name)
}
return layersNameArray
}
getData().done(onComplete)
I'm far from an expert with asynchronous calls, but I think this one is supposed to work. If I stock the getData() result in a variable and run the onComplete() function line by line, the code works. But when I run the code with getData().done(onComplete), it always fails at the var result = parser.read(data.responseText);line with Assertion error: Failure.
Any idea why this isn't working ?
Edit:
This code works, but nothing is returned. I want the function to output the layersNameArrayvariable. How should I proceed ?
function getData() {
$.ajax({
url: "http://localhost:8080/geoserver/ows?service=wms&version=1.1.0&request=GetCapabilities",
type: 'GET',
success: function(response) {
var parser = new ol.format.WMSCapabilities();
var result = parser.read(response);
var layersArray = result.Capability.Layer.Layer;
layersNameArray = [];
for(i=0;i<layersArray.length;i++){
layersNameArray.push(layersArray[i].Name)
}
return layersNameArray
}
});
}
You can make use of the Jquery callback feature,
make a call to your function this way,
getData(function(responsefromAjax){
alert('the response from ajax is :' +responsefromAjax);
// what ever logic that needs to run using this ajax data
});
And the make change to your method this way.
function getData(callback) { // passing the function as parameter
$.ajax({
url: "http://localhost:8080/geoserver/ows?service=wms&version=1.1.0&request=GetCapabilities",
type: 'GET',
success: function(response) {
var parser = new ol.format.WMSCapabilities();
var result = parser.read(response);
var layersArray = result.Capability.Layer.Layer;
layersNameArray = [];
for(i=0;i<layersArray.length;i++){
layersNameArray.push(layersArray[i].Name)
}
callback(layersNameArray); //this will execute your function defined during the function call. As you have passed the function as parameter.
}
});
}
Let me know if this helps
I'm working on creating a Users collection with the ability to then grab single users inside. This will be used to match from another system, so my desire is to load the users once, and then be able to fine/match later. However, I'm having a problem accessing the outer users collection from an inner method.
function Users(){
var allUsers;
this.getUsers = function () {
// ajax to that Jasmine behaves
$.ajax({
url: '../app/data/jira_users.json',
async: false,
dataType: 'json',
success: function(data) {
allUsers = data;
}
});
return allUsers;
};
this.SingleUser = function (name) {
var rate = 0.0;
var position;
this.getRate = function () {
if(position === undefined){
console.log('>>info: getting user position to then find rate');
this.getPosition();
}
$.ajax({
url: '../app/data/rates.json',
async: false,
dataType: 'json',
success: function(data) {
rate = data[position];
}
});
return rate;
};
this.getPosition = function () {
console.log(allUsers);
//position = allUsers[name];
return position;
};
//set name prop for use later I guess.
this.name = name;
};
}
and the test that's starting all of this:
it("get single user's position", function(){
var users = new Users();
var someone = new users.SingleUser('bgrimes');
var position = someone.getPosition();
expect(position).not.toBeUndefined();
expect(position).toEqual('mgr');
});
The getPosition method is the issue (which might be obvious) as allUsers is always undefined. What I have here is yet another attempt, I've tried a few ways. I think the problem is how the Users.getUsers is being called to start with, but I'm also unsure if I'm using the outer and inner vars is correct.
Though the others are correct in that this won't work as you have it typed out, I see the use case is a jasmine test case. So, there is a way to make your test succeed. And by doing something like the following you remove the need to actually be running any kind of server to do your test.
var dataThatYouWouldExpectFromServer = {
bgrimes: {
username: 'bgrimes',
show: 'chuck',
position: 'mgr'
}
};
it("get single user's position", function(){
var users = new Users();
spyOn($, 'ajax').andCallFake(function (ajaxOptions) {
ajaxOptions.success(dataThatYouWouldExpectFromServer);
});
users.getUsers();
var someone = new users.SingleUser('bgrimes');
var position = someone.getPosition();
expect(position).not.toBeUndefined();
expect(position).toEqual('mgr');
});
This will make the ajax call return whatever it is that you want it to return, which also allows you to mock out tests for failures, unexpected data, etc. You can set 'dataThatYouWouldExpectFromServer' to anything you want at any time.. which can help with cases where you want to test out a few different results but don't want a JSON file for each result.
Sorta-edit - this would fix the test case, but probably not the code. My recommendation is that any time you rely on an ajax call return, make sure the method you are calling has a 'callback' argument. For example:
var users = new Users();
users.getUsers(function () {
//continue doing stuff
});
You can nest them, or you can (preferably) create the callbacks and then use them as arguments for eachother.
var users = new Users(), currentUser;
var showUserRate = function () {
//show his rate
//this won't require a callback because we know it's loaded.
var rate = currentUser.getRate();
}
var usersLoaded = function () {
//going to load up the user 'bgrimes'
currentUser = new users.SingleUser('bgrimes');
currentUser.getRate(showUserRate);
}
users.getUsers(usersLoaded);
your approach to fill the data in allUsers is flawed
the ajax call in jquery is async so every call to users.getAllUsers would be returned with nothing and when later the success function of the jquery ajax is called then allUsers would get filled
this.getUsers() won't work. Its returning of allUsers is independent from the ajax request that fetches the data, because, well, the ajax is asynchronous. Same with getRate().
You'll have to use a callback approach, where you call getUsers() with a callback reference, and when the ajax request completes, it passes the data to the callback function.
Something like:
this.getUsers = function (callback) {
// ajax to that Jasmine behaves
$.ajax({
url: '../app/data/jira_users.json',
async: false,
dataType: 'json',
success: function(data) {
callback(data);
}
});
};
And the call would be along the lines of:
var user_data = null;
Users.getUsers(function(data) {
user_data = data;
});
I have an issue with a method ive created for an object ive created. one of the methods requires a callback to another method. the problem is i cant add the data to the object that called the method. it keeps coming back as undefined. otherwise when i send the data to the console it is correct. how can i get the data back to the method?
var blogObject = new Object();
var following = [...];
//get posts from those blogs
blogObject.getPosts = function () {
var followersBlogArray = new Array();
for (var i = 0; i < this.following.length;i++){
var followersBlog = new Object();
// get construct blog url
var complete_blog_url = ...;
i call the getAvatar function here sending the current user on the following array with it.
followersBlog.avatar = blogObject.getAvatar(this.following[i]);
that part goes smoothly
followersBlogArray.push(followersBlog);
}
this.followersBlogArray = followersBlogArray;
}
here is the function that gets called with the current user in following array
this function calls an ajax function
blogObject.getAvatar = function (data) {
console.log("get avatar");
var url = "..."
this ajax function does its work and has a callback function of showAvatar
$(function() {
$.ajax({
type: "GET",
dataType: "jsonp",
cache: false,
url: url,
data: {
jsonp:"blogObject.showAvatar"
}
});
});
}
this function gets called no problem when getAvatar is called. i cant however get it to add the data to the followersBlog object.
blogObject.showAvatar = function (avatar) {
return avatar
}
everything in here works fine but i cant get the showAvatar function to add to my followersBlog object. ive tried
blogObject.showAvatar = function (avatar) {
this.followersBlog.avatar = avatar;
return avatar
}
that didnt work of course. it shows up as undefined. can anyone help?
so somethings like...
$(function() {
$.ajax({
type: "GET",
dataType: "jsonp",
cache: false,
url: url,
complete: function () {
this.avatar = data;
}
data: {
jsonp:"blogObject.showAvatar"
}
});
});
}
Welcome to the world of asynchronous programming.
You need to account for the fact that $.ajax() will not return a value immediately, and Javascript engines will not wait for it to complete before moving on to the next line of code.
To fix this, you'll need to refactor your code and provide a callback for your AJAX call, which will call the code that you want to execute upon receiving a response from $.ajax(). This callback should be passed in as the complete argument for $.ajax().
The correct option for setting the JSONP callback is jsonpCallback. The recommendation from the API for .ajax(...) is to set it as a function.
{
// ...
jsonpCallback: function (returnedData) {
blogObject.showAvatar(returnedData);
},
// ...
}