JavaScript & jQuery: Calling inner functions [duplicate] - javascript

This question already has answers here:
JavaScript OOP with jQuery
(2 answers)
Closed 9 years ago.
I have the following code in JavaScript and jQuery with an integrated ajax request.
Question: Why is it possible to call the inner function success1() but it is not possible to call this.success2() ? Any solution proposals for this problem?
function myfuntion() {
this.url = "www.example.com/ajax.php";
var success1 = function (data) {
alert("SUCCESS1");
}
this.success2 = function (data) {
alert("SUCCESS2");
}
this.send = function () {
$.ajax({
type: "POST",
url: this.url,
dataType: "html"
}).done(function (data) {
success1(data);
this.success2(data);
});
}
}
var test = new myfunction().send();

As other commented, the context of this inside the send function is changed, so that's why your success2 function is not calling. You should save myFunction context in a variable and use that variable to refer this context.
Try this:
function myfuntion() {
var self = this; // taking the current context in a variable.
self.url = "www.example.com/ajax.php";
var success1 = function (data) {
alert("SUCCESS1");
}
self.success2 = function (data) {
alert("SUCCESS2");
}
self.send = function () {
$.ajax({
type: "POST",
url: self.url,
dataType: "html"
}).done(function (data) {
success1(data);
self.success2(data);
});
}
}

Related

JavaScript promises with nested AJAX calls are not working

On my code I hava a function with 3 nested AJAX calls, in order for it to work I had to set Async=false.
As I have read that Async=false is deprecated I replaced the Async=false with promises.
This is my function before I edited it:
self.getOrders = function (name) {
var orders= [];
var order= function (item, type1, type2) {
var self = this;
self.order= item;
self.type1= type1;
self.type2= type2;
}
$.ajax({
url: "/API/orders/" + name,
type: "GET",
async: false,
success: function (orderResults) {
var mappedOrders = $.map(orderResults, function (orderItem) {
$.ajax({
url: "/API/orders/property/" + orderItem.id + "/type1",
type: "GET",
async: false,
success: function (property1Results) {
$.ajax({
url: "/API/orders/property/" + orderItem.id + "/type2",
type: "GET",
async: false,
success: function (property2Results) {
orders.push(new order(orderItem, property1Results, property2Results));
}
});
}
});
})
}
});
return orders;
This function worked perfectly, I got the data end everything worked fine.
Then I changed the function to use promises instead of Async=false,
this is the edited function, with promises:
//The begin of the function- same as first one
var orders= [];
var firstPromise = $.ajax({
url: "/API/orders/" + name,
type: "GET"
});
$.when(firstPromise).done(function (orderResults) {
var mappedOrders = $.map(orderResults, function (orderItem) {
var secondPromise = $.ajax({
url: "/API/orders/property/" + orderItem.id + "/type1",
type: "GET"
});
$.when(secondPromise).done(function (property1Results) {
var thirdPromise = $.ajax({
url: "/API/orders/property/" + orderItem.id + "/type2",
type: "GET"
});
$.when(thirdPromise).done(function (property2Results) {
orders.push(new order(orderItem, property1Results, property2Results));
});
});
});
});
return orders;
And the function call:
self.populateOrders = function (name) {
var mappedOrders = $.map(self.service.getOrders(name), function (item) {
return new Order(item)
});
self.orders(mappedOrders);
}
The new function is not working, I'm getting back from the firstPromise a wrong json with backslashes, and the returned orders object is empty.
Any idea what am I doing wrong? I spent so much time on it but couldn't figure it out.
Thanks in advance.
Nested ajax calls inside a loop is a hell to manage. You can do it like this.
Create a promise to notify the caller when the whole process is finished
Wait for all the inner ajax calls to resolve
Resolve you main promise to notify the caller
self.getOrders = function (name) {
var mainDeferred = $.Deferred();
var orders = [];
var order = function (item, type1, type2) {
var self = this;
self.order = item;
self.type1 = type1;
self.type2 = type2;
}
$.ajax({
url: "/API/orders/" + name,
type: "GET",
success: function (orderResults) {
var innerwait = [];
var mappedOrders = $.map(orderResults, function (orderItem) {
var ajax1 = $.ajax({
url: "/API/orders/property/" + orderItem.id + "/type1",
type: "GET"
});
var ajax2 = $.ajax({
url: "/API/orders/property/" + orderItem.id + "/type2",
type: "GET"
});
$.when(ajax1, ajax2).done(function (property1Results, property2Results) {
orders.push(new order(orderItem, property1Results[0], property2Results[0])))
});
innerwait.push(ajax1, ajax2);
});;
$.when.apply(null, innerwait) //make sure to wait for all ajax requests to finish
.done(function () {
mainDeferred.resolve(orders); //now that we are sure the orders array is filled, we can resolve mainDeferred with orders array
});
}
});
return mainDeferred.promise();
}
self.populateOrders = function (name) {
self.service.getOrders(name).done(function (orders) { //use .done() method to wait for the .getOrders() to resolve
var mappedOrders = $.map(orders, function (item) {
return new Order(item)
});
self.orders(mappedOrders);
});
}
In the example, note that I use $.when.apply() to wait for an array of deferreds.
A bug recently introduced in chrome 52 (august 2016) can cause this kind of behavior : answers for nested requested are ignored.
Hoppefully, it will not last long.
https://bugs.chromium.org/p/chromium/issues/detail?id=633696
Try to add cache: false

Assign value to global variable using $.Ajax (JQuery)

I am creating new functionality where I build a grid based on Json data returned from Ajax. I have decided I want to encapsulate this functionality within a function, so when I add/update/delete, I can on success retrieve a new representation of the data.
The problem I am having is I want to fill a global array but once my function that uses AJAX ends, I have an Array but no data. This isn't a problem when all the code is within the AJAX call but once I try to separate this in to its own function, it doesn't work as intended.
<script type="text/javascript">
var DataArray = [];
// Use this function to fill array
function retrieveNotes() {
$.ajax({
url: "http://wks52025:82/WcfDataService.svc/GetNotesFromView()?$format=json",
type: "get",
datatype: "json",
asynch:true,
success: function (data) {
returnedData = data;
$.each(data.d, function (i, item) {
DataArray[i] = [];
DataArray[i][0] = item.NotesTitle.trim();
DataArray[i][1] = item.ProfileName.trim();
DataArray[i][2] = item.IsShared;
DataArray[i][3] = item.NameOfUser.trim();
}) // End of each loop
}
});
}
$(document).ready(function () {
retrieveNotes();
DataArray;
</script>
It's asynchronous, so you'll have to wait for the ajax call to finish before you can use the data :
function retrieveNotes() {
return $.ajax({
url: "http://wks52025:82/WcfDataService.svc/GetNotesFromView()?$format=json",
type: "get",
datatype: "json"
});
}
$(document).ready(function () {
retrieveNotes().done(function(data) {
var DataArray = [];
$.each(data.d, function (i, item) {
DataArray[i] = [];
DataArray[i][0] = item.NotesTitle.trim();
DataArray[i][1] = item.ProfileName.trim();
DataArray[i][2] = item.IsShared;
DataArray[i][3] = item.NameOfUser.trim();
});
// you can only use the data inside the done() handler,
// when the call has completed and the data is returned
});
});

Javascript: Setting class property from ajax success

I have a "class"/function called Spotlight. I'm trying to retrieve some information through ajax and assign it to a property of Spotlight. Here is my Spotlight class:
function Spotlight (mId,mName) {
this.area = new Array();
/**
* Get all area information
*/
this.getArea = function () {
$.ajax({
url: base_url +'spotlight/aGetArea',
type: 'POST',
success: function (data) {
this.area = data;
}
});
}
}
I have assigned the object to an array, and it would be difficult to get to it from within Spotlight, so I'm hoping to access everything using 'this.' It appears though that the success function is outside of the class, and I don't know how to make it inside the class.
Is there a way to get the data into the class property using this.area rather than Spotlight.area?
The value of this is dependent on how each function is called. I see 3 ways around this problem:
1. Creating an alias to this
var that = this;
this.getArea = function () {
$.ajax({
url: base_url +'spotlight/aGetArea',
type: 'POST',
success: function (data) {
that.area = data;
}
});
};
2. Using jQuery .ajax context option
this.getArea = function () {
$.ajax({
url: base_url +'spotlight/aGetArea',
type: 'POST',
context : this,
success: function (data) {
this.area = data;
}
});
};
3. Using a bound function as the callback
this.getAreaSuccess = function (data) {
this.area = data;
};
this.getArea = function () {
$.ajax({
url: base_url +'spotlight/aGetArea',
type: 'POST',
success: this.getAreaSuccess.bind(this)
});
};
Well Spotlight.area wouldn't work anyway. You just need to preserve the outer this:
this.area = [];
var theSpotlight = this;
and then in the callback:
theSpotlight.area = data;
When inside the success function, this corresponds to the scope of the success function.
function Spotlight (mId,mName) {
this.area = [];
var scope = this;
/**
* Get all area information
*/
this.getArea = function () {
$.ajax({
url: base_url +'spotlight/aGetArea',
type: 'POST',
success: function (data) {
scope.area = data;
}
});
}
}

$.Ajax Success Invoke Prototype Function Error [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
$(this) inside of AJAX success not working
I have the following sample code (JSFiddle to follow)
AdvancedSearch = function() {
this.current = 'test';
}
AdvancedSearch.prototype.InitPage = function() {
var t = this.current;
this.PrePopulate()
}
AdvancedSearch.prototype.UpdateData= function() {
alert(this.current);
}
AdvancedSearch.prototype.PrePopulate = function() {
this.UpdateData();
$.ajax({
url: 'http://fiddle.jshell.net/',
success: function(msg) {
this.UpdateData();
}
});
}
var as = new AdvancedSearch();
as.InitPage();​
I have the 'http://fiddle.jshell.net' in there so prevent the Access-Control-Allow-Origin error on their site.
When executing this code, I get the following error:
Uncaught TypeError: Object # has not method 'UpdateData'
If you execute the JSFiddle, you will find that when PrePopulate is called, it runs the this.UpdateData() at the beginning of the function just fine. But as soon as the Ajax call is finished, you get the error.
Any thoughts to why this is happening? Perhaps I'm approaching this in the wrong way. Any insight would help.
Here is my JSFiddle: http://jsfiddle.net/B4NRY/2/
The callback you give to $.ajax isn't called with your instance of AdvancedSearch as context (this).
Solution 1 (valid for all the similar callback problems ) :
AdvancedSearch.prototype.PrePopulate = function() {
this.UpdateData();
var that = this; // register the that variable in the closure of the callback
$.ajax({
url: 'http://fiddle.jshell.net/',
success: function(msg) {
that.UpdateData();
}
});
}
Solution 2 (specific to $.ajax but very clean, thanks Felix) :
AdvancedSearch.prototype.PrePopulate = function() {
this.UpdateData();
$.ajax({
url: 'http://fiddle.jshell.net/',
context: this,
success: function(msg) {
this.UpdateData();
}
});
}

jquery function access local javascript variable

New to jQuery and having simple yet confusing problem. ha2.
I am writing this normal javascript function with jQuery function reading xml file. How do I assigned value to the prodPrice variable declared on the top? the script keep returning 0 value, but if I alert the value within the jQuery function, I managed to get the value that I wanted.
Thank you guys.
function getPrice(valprodID)
{
var prodPrice=0;
jQuery.ajax({
type: "GET",
url: "products.xml",
dataType : "xml",
success : function(xml)
{
jQuery(xml).find('prod').each(function(){
var prodID = jQuery(this).find('prodID').text();
if(prodID == valprodID)
{
prodPrice = jQuery(this).find('prodPrice').text();
return false;
}
});
}
})
return prodPrice;
}
That's because $.ajax is performed asynchronously.
And it is a great chance for you to learn how to work with $.Deferred
function getPrice(valprodID)
{
var prodPrice=0;
return jQuery.ajax({
type: "GET",
url: "products.xml",
dataType : "xml"
}).pipe(function(xml)
{
jQuery(xml).find('prod').each(function(){
var prodID = jQuery(this).find('prodID').text();
if(prodID == valprodID)
{
return jQuery(this).find('prodPrice').text();
}
});
});
}
Now you call your getPrice() function in this way:
getPrice(someid).done(function(prodPrice) {
// do what you need with prodPrice
});
Here is an example on jsfiddle: http://jsfiddle.net/zerkms/9MgsX/1/
you can do asynchronous as reported by #xdazz, as #zerkms indicated with Deferred, or anonymous functions:
function getPrice(valprodID, fn)
{
var prodPrice=0;
jQuery.ajax({
type: "GET",
url: "products.xml",
dataType : "xml",
success : function(xml)
{
jQuery(xml).find('prod').each(function(){
var prodID = jQuery(this).find('prodID').text();
if(prodID == valprodID)
{
prodPrice = jQuery(this).find('prodPrice').text();
fn(prodPrice);
}
});
}
})
}
getPrice(1, function(prodPrice) {
/* your code */
})
You need to set the async option to false, or you should do your work in the callback function.

Categories