state not updating after AJAX call using setState() - ajax

I am not getting state updated after making a AJAX call in componentDidMount. My api call is returning the correct data .
Any ideas if I am doing setState in wrong lifecycle component? Making the AJAX request in the componentDidMount and also setting the new state there. In the constructor I set the state to empty arrays
class DeliveryDateInput extends React.Component {
constructor(props) {
super(props);
this.getDeliveryDate = this.getDeliveryDate.bind(this);
this.state = {
selectDate: selectedDate || validDelDateArray[0],
validDeliveryDateArray: validDelDateArray,
firstDeliveryDay: [],
lastDeliveryDay: [],
selectedDate: [],
deliveryDatesAllowed: [],
offDays: [],
};
}
componentDidMount () {
console.log('App componentDidMount');
this.getDeliveryDate();
}
componentWillUpdate(nextProps, nextState) {
this.getDeliveryDate();
console.log('Your prev offday state: ' + this.state.offday);
console.log('Your next offday state: ' + nextState.offday);
}
getDeliveryDate() {
const self = this;
$.ajax({
type: 'GET',
url: //deliveryDateAPI,
contentType: 'application/json; charset=utf-8',
success(data) {
self.setState({
firstDeliveryDay: data.firstDeliveryDate,
lastDeliveryDay: data.lastDeliveryDay,
selectedDate: data.firstDeliveryDate,
deliveryDatesAllowed: data.deliveryDates,
offDays: data.offDays,
});
},
failure(errMsg) {
console.log(errMsg);
},
});
}

In React, you will have to bind ajax callback functions to the component (which is .bind(this))
You knew this and have done similar thing in your constructor, but for the jquery ajax, it will look a bit different like: (and the self variable is unnecessary here)
getDeliveryDate() {
$.ajax({
type: 'GET',
url: //deliveryDateAPI,
contentType: 'application/json; charset=utf-8',
success: function(data) {
this.setState({
firstDeliveryDay: data.firstDeliveryDate,
lastDeliveryDay: data.lastDeliveryDay,
selectedDate: data.firstDeliveryDate,
deliveryDatesAllowed: data.deliveryDates,
offDays: data.offDays,
});
}.bind(this),
error: function(errMsg) {
console.log(errMsg);
}.bind(this),
});
}
I've tested the above code and it works. You may not need to bind the error callback since you don't do anything yet to the component, but maybe it's still necessary if you want to make further actions there!
If this doesn't work yet, please comment here the errors on your console, thanks!
ADDED MODIFICATION:
Please remove the ajax call in your componentWillUpdate, which will create a "forever" loop:
componentWillUpdate(nextProps, nextState) {
//this.getDeliveryDate();
console.log('Your prev offday state: ' + this.state.offday);
console.log('Your next offday state: ' + nextState.offday);
}
The reason is: actually, after a state is set, componentWillUpdate() will be executed, and here if you run the ajax call again, after that it will setState again, then the loop will last forever!

Related

Return bool value from Ajax

I am calling the below function from my .aspx page and all I want to check whether this function returned true or false. I tried many things but I get undefined as result.
I am calling function using below code
if (IsIncetiveAllowed())
{
sCondition = ".//LISTENTRY[VALUEID='" + m_sIncentiveReleaseId + "']";
xmlNode = $(XMLCombos).xpath(sCondition)[0];
XMLCombos.firstChild.removeChild(xmlNode);
}
function IsIncetiveAllowed() {
$.ajax({
cache: false,
async: false,
type: "POST",
url: "pp060.aspx/CheckIncentiveAllowed",
data: "{'typeOfApplication': '" + m_TypeOfMortgage + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
if (response.d)
return true;
else
return false;
},
error: function (response) {
MessageBox.Show("An error occurred checking IsIncetiveAllowed method.", null, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
});
}
Please Help!
If you pass a callback to the IsIncetiveAllowed function, you can make it execute your code with the result of the ajax call after it has been made.
IsIncetiveAllowed(function(is_allowed) {
if (is_allowed) {
sCondition = ".//LISTENTRY[VALUEID='" + m_sIncentiveReleaseId + "']";
xmlNode = $(XMLCombos).xpath(sCondition)[0];
XMLCombos.firstChild.removeChild(xmlNode);
}
else {
// Not allowed
}
});
function IsIncetiveAllowed(callback) {
$.ajax({
cache: false,
async: false,
type: "POST",
url: "pp060.aspx/CheckIncentiveAllowed",
data: "{'typeOfApplication': '" + m_TypeOfMortgage + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
if (response.d)
callback(true);
else
callback(false);
},
error: function (response) {
MessageBox.Show("An error occurred checking IsIncetiveAllowed method.", null, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
});
}
First off, you never want to use synchronous Ajax. Synchronous Ajax blocks the browser, the user interface freezes and the user cannot scroll, click or do or anything while synchronous requests load. Don't use them.
Second, it's useful to break up your operation into separate parts. What you have here is
A part can post JSON to the server
This is the most re-usable part, it works the same for all JSON you want to post to any URL.
A part that knows how to talk to to a specific endpoint on the server
This is the second most reusable part, it can send any data to a specific endpoint.
A part that uses this endpoint
This is the least reusable part, it can send specific data to a specific endpoint.
It makes sense to have a separate function for each part. jQuery supports this easily, because all Ajax methods return promises, and promises can be given from function to function.
Part 1, as a jQuery extension for maximum re-usability:
$.fn.postJSON = function(url, data) {
return $.ajax({
type: "POST",
url: url,
contentType: "application/json; charset=utf-8",
data: JSON.stringify(data)
});
};
Part 2, as a stand-alone function. Note that I am matching the remote API endpoint name. You can write more functions like this to wrap other API endpoints.
function checkIncentiveAllowed(typeOfApp) {
return $.postJSON("pp060.aspx/CheckIncentiveAllowed", {
typeOfApplication: typeOfApp
}).fail(function (err) {
MessageBox.Show("An error occurred in checkIncentiveAllowed method.",
null, MessageBoxButtons.OK, MessageBoxIcon.Error);
console.log(err);
});
}
Part 3, to be used inside an event handler for example:
checkIncentiveAllowed(m_TypeOfMortgage).done(function (response) {
var path = ".//LISTENTRY[VALUEID='" + m_sIncentiveReleaseId + "']",
xmlNode = $(XMLCombos).xpath(path)[0];
if (response.d && xmlNode) {
xmlNode.parentNode.removeChild(xmlNode);
} else {
// not allowed
}
});
Well this is happening because the ajax call is asynchronous. You can put your code present in if block to the ajax callback function to implement your logic

Ajax Call to mvc controller action is very slow when SignalR is fetching data

My App Flow
In my App - Dashboard,
I have the SignalR scripts included which fetches new data as and when new data arrives from the device
It also has ajax script that hits on the Controller to fetch data from the back end - when a Get button is clicked.
Ajax Call mentioned in #2 above takes more than 2 minutes if new data keeps getting in (i.e when SignalR is continuously fetching data and publishing to all connected clients).
Else
the Ajax Call Point#2 above takes very less time to get the data.
Any ideas, better way, ... on how I can avoid the slowness in the ajax call #2 even if SignalR continuously fetches data.
This is my #2 Ajax Call ==> Call to the Home Controller Action Method SignalList
$('#DeviceID').on('change', function () {
$('#DeviceName').text("Device : " + $('#DeviceID option:selected').text());
$.ajax({
url: "/Home/SignalList",
type: "POST",
data: { deviceID: $('#DeviceID').val() },
//contentType: "application/json; charset=utf-8",
dataType: "html",
//cache: false,
//async: true,
success: function (result) {
//alert("AAA");
$('#signalCheckListBox').html(result);
},
failure: function (response) {
alert(response.responseText);
},
error: function (response) {
alert(response.responseText);
}
});
This is SignalR script
(function () {
// Defining a connection to the server hub.
var signalHub = $.connection.signalHub; //alert("ACCC");
// Setting logging to true so that we can see whats happening in the browser console log. [OPTIONAL]
$.connection.hub.logging = true;
// Start the hub
$.connection.hub.start();
// This is the client method which is being called inside the SignalHub constructor method every 3 seconds
signalHub.client.SendSignalData = function (signalData) {
dModel = signalData;
updateSignalData(signalData);//<============ # Statekemnt A
};
$.connection.hub.disconnected(function () {
setTimeout(function () {
$.connection.hub.start();
}, 5000); // Restart connection after 5 seconds.
}); }());
The statement A marked above is a method which (1)updates different html elements in the UI and also (2)sends an email on a condition.
For sending the email too it hits the same controller Home (??? Would that be the problem???)
The email ajax call is below ==> Its a call to Home Controller Action Method Communicate
function email(alarmSignalInfo) {
$.ajax({
url: "/Home/Communicate",
type: "POST",
dataType: "json",
//data: { alarmSignalInfo: JSON.stringify(alarmSignalInfo) },
data: { alarmSignalInfo: alarmSignalInfo },
//cache: false,
//async: true,
success: function (result) { onSuccess(result); }
}); }

server redirect inside public shared function

I have a ajax call happening for the java script which is this.
<System.Web.Services.WebMethod()>
Public Shared Function Finalize()
try
Sendemail1()
sendemail2()
doesomething()
Catch ex As Exception
ErrorMSg = -1
Throw ex
Finally
con.Close()
con.Dispose()
End Try
Return "success"
End Function
if there is a success then i am handing that on client side and want to redirect page to a different one. but i dont know why system never reach to the Success: or Error: or Complete: of the Ajax call. If i remove all three internal Public Shared Function then it works as expected.
Public Shared Function Sendemail1()
'''' Send email
End Function
Public Shared Function Sendemail2()
'''' Send email
End Function
Public Shared Function doesomething()
'''' Update database
End Function
as i explain i want to redirect to a different page when all the function are completed. I tired adding
HttpContext.Current.Response.Redirect("MyPage.aspx")
at the end of third public shared function and redirection didnt happen.
I also tried adding that after the call of third function in the main Ajax call, still nothing happen.
Am i missing something here. What is the proper way to resolve this issue.
Client side Code:
<script type = 'text/javascript'>
$(document).ready(function () {
var userConfirmation = window.confirm('Are you sure?\nPress OK to continue.\nPress CANCEL to stop the process.');
if (userConfirmation == false) {
return 0;
}
else {
$.ajax
({
type: 'POST',
//url: 'NewSubmission.aspx/function1',
url: 'NewSubmission.aspx/FinalizeSub',
data: JSON.stringify({ id:193, SubType:1, Exception:0, PageNum:12, Authors:1 }),
//data: '{sessionval: '' + data1 + '' }',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: OnSuccess,
failure: function (response) {
alert(response.d);
},
Error: function (response) {
alert(response.d);
},
Complete: function (response) {
alert(response.d);
}
});
function OnSuccess(data) {
alert(data.d);
/// Redirection will heppen here
}
}
});
</script>
PS:i also don't see an error messages on the browser console.

Ajax wait on success before next iteration in .each loop

I have an ajax call inside a .each loop wrapped in a setInterval function.
This handles updating of many divs on a dashboard with just a few lines of code on the html page.
I am worried about server lag vs client side speed. What will happen if the server has not responded with the data before the loop moves on to the next iteration?
So, my question is, can the loop be paused until the success is executed?
Ajax call:
setInterval(function() {
$(".ajax_update").each(function(){
$.ajax({
type: "POST",
dataType: "json",
url: "ajax/automated_update/confirmed_appointments.php",
data: "clinic_id=<? echo $clinic_id ?>&tomorrow=<? echo $tomorrow ?>&"+$(this).data('stored'), // serializes the form's elements.
success: function(data)
{
$(data[0]).html(data[1]);
}
});
});
}, 5000); //5 seconds*
</script>
I have looked into .ajaxComplete() but I dont see how to apply this as a solution.
I have also looked at turning the loop into something that calls itself like:
function doLoop() {
if (i >= options.length) {
return;
}
$.ajax({
success: function(data) {
i++;
doLoop();
}
});
}
But would that not interfere with .each? I dont understand how that would play nice with .each and looping based on my div class.
I just cant figure it out! Any help would be appreciated.
I was able to get .when working with the ajax call, but I dont understand how to make .when do what I need (stop the loop until the ajax call is done).
$(".ajax_update").each(function(){
$.ajax({
type: "POST",
dataType: "json",
url: "ajax/automated_update/confirmed_appointments.php",
data: "clinic_id=<? echo $clinic_id ?>&tomorrow=<? echo $tomorrow ?>&"+$(this).data('stored'), // serializes the form's elements.
success: function(data)
{
$(data[0]).html(data[1]);
}
});
$.when( $.ajax() ).done(function() {
alert("Finished it");
});
});
After thinking about your question a bit, perhaps a good solution would be to put an event in place that would trigger a new set of updates with a minimum time between your dashboard updates. This would ensure that all your updates process, that we do wait a minimum time between updates and then trigger the update cycle once again. Thus if you DO encounter any delayed ajax responses you do not try another until the previous one has all completed.
I have not fully tested this code but is should do what I describe:
//create a dashboard object to handle the update deferred
var dashboard = {
update: function (myquery) {
var dfr = $.Deferred();
$.ajax({
type: "POST",
dataType: "json",
url: "ajax/automated_update/confirmed_appointments.php",
data: "clinic_id=<? echo $clinic_id ?>&tomorrow=<? echo $tomorrow ?>&" + myquery,
success: dfr.resolve
});
return dfr.promise();
}
};
//create a simple deferred wait timer
$.wait = function (time) {
return $.Deferred(function (dfd) {
setTimeout(dfd.resolve, time);
});
};
// use map instead of your .each to better manage the deferreds
var mydeferred = $(".ajax_update").map(function (i, elem) {
return dashboard.update($(this).data('stored')).then(function (data, textStatus, jqXHR) {
$(data[0]).html(data[1]);
});
});
//where I hang my dashboardupdate event on and then trigger it
var mydiv = $('#mydiv');
var minimumDashboardUpdate = 5000;
$('#mydiv').on('dashboardupdate', function () {
$.when.apply($, mydeferred.get())
.then(function () {
$.when($.wait(minimumDashboardUpdate)).then(function () {
mydiv.trigger('dashboardupdate');
});
});
});
mydiv.trigger('dashboardupdate');

Sapui5 navTo not working in ajax statement

I have a form in my page. When a user clicks a button if have no problem this code must navigate my Tile page. I am taking this problem:Uncaught TypeError: Cannot read property 'navTo' of undefined.
This my code:
onPressGonder: function (evt) {
var sURL = "xxxxxx";
$.ajax({
url: sURL,
dataType: "json",
success: function(data) {
if (data.ResultCode === 7) {
sap.m.MessageToast.show("Error:" +data.Alerts[0].Message+"") ;
} else {
sap.m.MessageToast.show("Login succesfull.");
sap.ui.core.UIComponent.getRouterFor(this).navTo("Tile");
}
}
});
}
You are having a scope problem. The function provided as a success callback is a anonymous function called later on by jQuery.ajax. Therefore it is NOT a method of your controller and thereby does not know this. By default (as in your anonymous function) this refers to the window object. So what your basically doing is:
sap.ui.core.UIComponent.getRouterFor(window).navTo("Tile");
And the window object obviously does not have a router or a navTo method ;)
The easiest workaround is to make this available via the closure scope as follows:
onPressGonder: function (evt) {
var sURL = "xxxxxx",
that = this;
$.ajax({
url: sURL,
dataType: "json",
success: function(data) {
if (data.ResultCode === 7) {
sap.m.MessageToast.show("Error:" +data.Alerts[0].Message+"") ;
} else {
sap.m.MessageToast.show("Login succesfull.");
sap.ui.core.UIComponent.getRouterFor(that).navTo("Tile");
}
}
});
}
Another probably more elegant solution is to use the context property of jQuery.ajax. It will ensure that any ajax callback will be executed with the provided context (meaning whatever you pass as a context will be referred to as this inside your callbacks):
$.ajax({
...
success: function(data) {
...
sap.ui.core.UIComponent.getRouterFor(this).navTo("Tile");
},
context: this
});

Resources