Accessing JavaScript variable outside of $.each() function - javascript

I'm having trouble passing a variable declared in an $.each() function to Prototype function. I'm receiving the error Uncaught ReferenceError: prices is not defined
Compare.prototype.results = function (answers) {
$.ajax({
type: 'POST',
dataType: 'json',
data: {
answers: answers
},
success: function (data) {
$.each(data, function (index, dataItem) {
var prices = [],
priceData = dataItem.pricing_term,
priceObj = JSON.parse(priceData);
$.each(priceObj, function (term, pricing) {
prices.push(term, pricing);
});
});
Compare.prototype.show(data, prices);
}
});
}
I want to be able to populate the prices variable and pass it to be used with the data that is originally returned from the ajax call. I am new to javascript, if there is a cleaner way to go about writing this please let me know.

It's out of scope
Compare.prototype.results = function (answers) {
$.ajax({
type: 'POST',
dataType: 'json',
data: {
answers: answers
},
success: function (data) {
var prices = [];
$.each(data, function (index, dataItem) {
var priceData = dataItem.pricing_term,
priceObj = JSON.parse(priceData);
$.each(priceObj, function (term, pricing) {
prices.push(term, pricing);
});
});
// same scope
Compare.prototype.show(data, prices);
}
});
}

You have declared your prices array within the scope of the first &.each function. This means you can only access the prices array in that function. You need to declare prices outside of the function, like so:
Compare.prototype.results = function (answers) {
$.ajax({
type: 'POST',
dataType: 'json',
data: {
answers: answers
},
success: function (data) {
var prices = [];
$.each(data, function (index, dataItem) {
var priceData = dataItem.pricing_term;
var priceObj = JSON.parse(priceData);
$.each(priceObj, function (term, pricing) {
prices.push(term, pricing);
});
});
Compare.prototype.show(data, prices);
}
});
}
This way, prices is available in any of the functions that are within the scope of the success function of the AJAX request.

Related

How do I make a function call execute first before executing subsequent codes? [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
I am trying to learn JS by building a random Quote Machine but this problem has been bugging me. I saw the other answers but I really couldn't understand them due to lack of context. Any help will be appreciated. The code is:
$(document).ready(function () {
$("#btn").click(function () {
getQuote(); //This should execute first, then the next lines
var quoteData = jSonify();
var quote = quoteData[0];
var author = quoteData[1];
console.log(quote);
console.log(author);
console.log("Button Clicked");//This Should execute last.
});
//Get them quotes
function getQuote() {
$.ajax({
url: 'https://andruxnet-random-famous-quotes.p.mashape.com/?cat=famous',
type: 'GET',
data: {},
datatype: 'json',
success: function (data) { jSonify(data); },
error: function (err) { alert(err); },
beforeSend: function (xhr) {
xhr.setRequestHeader("X-Mashape-Authorization", "qKPbfOzWKemsh2qi30QgbOA1WufXp1ok1NsjsnAkvh6yVJfaAk");
}
});
}
//Convert to jSon
function jSonify(rawData) {
var jSonified = jQuery.parseJSON(rawData);
var quote = jSonified.quote;
var author = jSonified.author;
console.log(quote);
console.log(author);
return [quote, author];
}});
getQuote() won't be done by the time JavaScript runs the next line, var quoteData = jSonify();. This is because it has a $.ajax call inside of it, which could take a long time to complete.
getQuote won't be done until the success method in the $.ajax method is called.
So what you need to do is pass a callback into getQuote, like so:
$("#btn").click(function () {
getQuote(function() {
var quoteData = jSonify();
var quote = quoteData[0];
var author = quoteData[1];
console.log(quote);
console.log(author);
console.log("Button Clicked");
});
});
//Get them quotes
function getQuote(done) {
$.ajax({
url: 'https://andruxnet-random-famous-quotes.p.mashape.com/?cat=famous',
type: 'GET',
data: {},
datatype: 'json',
success: function (data) { jSonify(data); done(); }, // Call the callback!
error: function (err) { alert(err); },
beforeSend: function (xhr) {
xhr.setRequestHeader("X-Mashape-Authorization", "qKPbfOzWKemsh2qi30QgbOA1WufXp1ok1NsjsnAkvh6yVJfaAk");
}
});
}
The callback will only be called once the ajax has actually finished. Once it's called, the rest of the computation will take place.
you can embed later to be called statements inside ajax success
$(document).ready(function () {
$("#btn").click(function () {
getQuote(); //This should execute first, then the next lines
});
//Get them quotes
function getQuote() {
$.ajax({
url: 'https://andruxnet-random-famous-quotes.p.mashape.com/?cat=famous',
type: 'GET',
data: {},
datatype: 'json',
success: function (data) {
var quoteData = jSonify(data);
var quote = quoteData[0];
var author = quoteData[1];
console.log(quote);
console.log(author);
console.log("Button Clicked");//This Should execute last.
},
error: function (err) { alert(err); },
beforeSend: function (xhr) {
xhr.setRequestHeader("X-Mashape-Authorization", "qKPbfOzWKemsh2qi30QgbOA1WufXp1ok1NsjsnAkvh6yVJfaAk");
}
});
}
//Convert to jSon
function jSonify(rawData) {
var jSonified = jQuery.parseJSON(rawData);
var quote = jSonified.quote;
var author = jSonified.author;
console.log(quote);
console.log(author);
return [quote, author];
}});

How to combine multiple call to Ajax Data base from different JS files

I have some code on a file that makes Ajax calls. This file is being called as a function by multiple other files that creates a new instance each time.
This is the JS code that is being called:
define(["underscore", "homeop", "domReady!"],
function (_, homeop, domready) {
var timeout = 500;
return function (opUrl, opList, onCallback) {
// IRRELEVANT CODE
var getFetch = function (optionName) {
$.ajax({
url: optionsUrl,
data: { optionNames: [optionName] },
type: "POST",
dataType: "json",
async: false,
traditional: true,
success: function (data) {
_.each(data, function (optionData, optionName) {
if (homeop.globalCache[optionName] === null) {
homeop.globalCache[optionName] = optionData;
}
});
},
error: function (message) {
console.error(message.responseText);
}
});
};
self.getInfo = function (optionName) {
if (homeop.globalCache[optionName] === undefined) {
if (!_.contains(homeop.getOption(), optionName)) {
getFetch(optionName);
}
// MORE IRRELEVANT CODE GOES HERE
In other JS files, I call the get function; for example
var these = new getOptions(optionsUrl, optionsList, onLoadCallback);
var getOpt = these.get(OptionsUrl);
The problem is I am making multiple calls to the get information from the database causing multiple call to my JS file. Each new instance of the JS file will create a ajax call.
Is there a way to wait for all the calls to be done and then get data from the database? In other words how can I somehow combine all the call to my 'getOption.js'?
Thanks
Try this.. You can also implement queue in place of stack
var optionStack = [];
var isAvailable = true;
var getFetch = function (optionName) {
if(isAvailable){
isAvilable = false; // function not available now
}
else {
optionStack.push(optionName)
return;
}
$.ajax({
url: optionsUrl,
data: { optionNames: [optionName] },
type: "POST",
dataType: "json",
async: false,
traditional: true,
success: function (data) {
_.each(data, function (optionData, optionName) {
if (homeop.globalCache[optionName] === null) {
homeop.globalCache[optionName] = optionData;
}
});
},
error: function (message) {
console.error(message.responseText);
},
done: function (){
isAvailable = true;
if(optionStack.length > 0){
getFetch(optionStack.pop());
}
}
});
};

Bind observable array using AJAX inside function

I'am using Knockout.js. I have a function like this:
function deviceGroupItem(item) {
this.DeviceGroupName = item.DeviceGroupName;
this.groupDevicesVisible = ko.observable(false)
this.groupDevicesArray = ko.observableArray();
this.deviceGroupClick = function () {
if (this.groupDevicesVisible() == false) {
this.groupDevicesVisible(true)
$.ajax({
url: returnServer() + '/api/Mobile/getRoomDevices?accessToken=' + localStorage.getItem('Token'),
type: "GET",
dataType: "json",
success: function (data) {
this.groupDevicesArray()($.map(data, function (item) {
return new roomDeviceItem(item);
}))
},
error: function () {
}
})
} else {
this.groupDevicesVisible(false)
}
}
return this;
}
Problem is, when I'am trying bind:
this.groupDevicesArray = ko.observableArray();
Using:
this.groupDevicesArray()($.map(data, function (item) {
return new roomDeviceItem(item);
}))
I'am receiving error "this.groupDevicesArray is not a function". Honestly, I dont know how to do this in correct way. Do You know how can I achieve that?
The issue is because of you referring observable Array with this inside the function deviceGroupClick which does not exist because this refers to current context .
This technique depends on current closure which is a pseudo variable
that may differ from scope to scope dynamically .
viewModel:
function roomDeviceItem(data) {
this.room = ko.observable(data.room)
}
function deviceGroupItem() {
var self=this; //Assign this to self & use self everywhere
self.groupDevicesArray = ko.observableArray();
self.deviceGroupClick = function () {
$.ajax({
url: '/echo/json/',
type: "GET",
dataType: "json",
success: function (data) {
data = [{
'room': 'One'
}, {
'room': 'Two'
}]
self.groupDevicesArray($.map(data, function (item) {
return new roomDeviceItem(item);
}))
}
});
};
};
ko.applyBindings(new deviceGroupItem());
working sample here
Just in-case if you are looking for solution with this you need to use bind(this) to get reference of outer closure check here
Try
this.groupDevicesArray($.map(data, function (item) {
return new roomDeviceItem(item);
}));
groupDevicesArray is observableArray and $.map returns an array.

jquery function inside class confusing this keyword

function chat() {
this.waittime = 6000;
this.intUpdate = null;
this.sendChatUpdate = function (msg) {
var Chatmsg = '0';
if (msg > 0) {
Chatmsg = $('#chatmsg');
var m = Chatmsg.val();
Chatmsg.val('');
}
var s = $("#chatnick").val();
var r = $("#chatto").val();
$.ajax({
type: 'POST',
url: 'Chat/ajax/Chat.php',
data: {
S: s,
R: r,
M: m
},
success: function (data) {
this.ProcessChatReturn(data);
},
error: function (data) {
this.ProcessChatReturn(data);
}
});
}
this.getUnreadChat = function (mr) {
var s = $("#chatnick").val();
$.ajax({
type: 'POST',
url: 'Chat/ajax/Chat.php',
data: {
S: s,
UR: 1,
MR: mr
},
success: function (data) {
this.ProcessChatReturn(data);
},
error: function (data) {
this.ProcessChatReturn(data);
}
});
//clearTimeout(intUpdate);
$('#chatbox').show();
}
}
var chat = new chat();
chat.getUnreadChat();
I am getting error "Uncaught TypeError: Object # has no method 'ProcessChatReturn' "
I think it is because if the use of "this" inside of the jquery ajax call. I want to reference my "chat" object but I think due to including it inside the jquery ajax function it is not.
Any suggestions how to reference my chat object in that location?
You cannot do that because this inside the ajax succes callback points to jqXHR object and not to your object context. You can instead cache the object to another variable and use it. There are numerous other ways too.
this.sendChatUpdate = function (msg) {
var Chatmsg = '0';
if (msg > 0) {
Chatmsg = $('#chatmsg');
var m = Chatmsg.val();
Chatmsg.val('');
}
var s = $("#chatnick").val();
var r = $("#chatto").val(), self = this; //Cache this to self.
$.ajax({
type: 'POST',
url: 'Chat/ajax/Chat.php',
data: {
S: s,
R: r,
M: m
},
success: function (data) {
self.ProcessChatReturn(data); //Invoke it with self
},
error: function (data) {
self.ProcessChatReturn(data); //Invoke it with self
}
});
}
You can also make use of context property of ajax settings.
Ex:
$.ajax({
type: 'POST',
url: 'Chat/ajax/Chat.php',
data: {
S: s,
R: r,
M: m
},
context:this, //set the context here
success: function (data) {
this.ProcessChatReturn(data); //Invoke it with this
},
error: function (data) {
this.ProcessChatReturn(data); //Invoke it with this
}
});
There are other ways as well like binding the callback function reference using Ecmascript5 function.bind or $.proxy , but in your case you can avoid those.
Note that a context inside a function refers to the context of the caller, or in other words where the function was invoked from (Except for bound function as mentioned in the last statements). In your case you gave a callback to ajax as your anonymous func reference and it gets invoked from jquery ajax object so by default the context points to that

knockout.js observableArray is not recognized as a function

I have been using knockout.js for a while now, and haven't encountered this problem before. Usually, when I try to push a new js object to an observableArray, it works without an issue, but for some reason, this time around I'm getting this error:
TypeError: self.Students.push is not a function
Here is a snippet of my code:
window.ApiClient = {
ServiceUrl: "/api/students",
Start: function () {
var viewModel = ApiClient.ViewModel(ngon.ClientViewModel);
ko.applyBindings(viewModel);
viewModel.get();
}
};
ApiClient.ViewModel = function(data) {
var self = this;
ko.mapping.fromJS(data, {}, this);
this.get = function (id) {
if (id == undefined) {
return ApiClient.Service.get(self.PageSize(), self.PageNumber(), function (data) {
self.Students(data);
});
}
}
this.post = function () {
return ApiClient.Service.post(self.DetailedStudent, function (data) {
self.Students.push(data);
});
}
return this;
}
ApiClient.Service = function () {
var _get = function (pageSize, pageNumber, callback) {
sv.shouldShowLoading = false;
var queryParams = String.format("?pageSize={0}&pageNumber={1}", pageSize, pageNumber);
$.ajax(ApiClient.ServiceUrl + queryParams, {
dataType: "json",
type: "get",
success: callback
});
}
var _post = function (student, callback) {
$.ajax(ApiClient.ServiceUrl, {
data: ko.mapping.toJSON(student),
type: "post",
contentType: "application/json; charset-utf-8",
statusCode: {
201 /*Created*/: callback,
400 /*BadRequest*/: function (jqxhr) {
var validationResult = $.parseJSON(jqxhr.responseText);
alert(jqxhr.responseText);
}
}
});
}
return {
get: _get,
post: _post
};
}();
$(document).ready(function () {
ApiClient.Start();
});
My student object is a very simple C# object that has Id, FirstName, LastName. The get() function works without any issues, it's just the callback function from the post() that cannot push the resulting data. Also, the data being returned back from the server looks correct:
{"Id":"rea","FirstName":"asdf","MiddleName":null,"LastName":"rrr"}
I solved this! It's because the initial viewModel, when being instantiated by the page's view model object had 'null' for its Students property.
knockout.js requires non-null values for all fields that are to be auto mapped.

Categories