Why does my variables reset inside ajax request? - javascript

I'm currently trying to use CanvasJS to render multiple charts on my page, and using AJAX to get the data for the tables. I'm using a loop on the AJAX to get the data values, and that's working fine atm, but I'm having problems on getting the value of a variable outside the AJAX.
This is the part I'm having problems with:
for(var i = 0; i < nMeses; i++) {
var mes = dtIni.addMonths(i);
var ano = mes.getFullYear();
mes = mes.getMonth()+1;
mes = (mes<10 ? '0' : '') + mes;
var res = ano + mes;
console.log(res);
$.ajax({
url: "getMesGrafico.php",
type: "GET",
dataType: "json",
data: {"m": mes},
success: function(data) {
console.log(res);
var chart = new CanvasJS.Chart("body"+res, {
animationEnabled: true,
theme: "light1", // "light1", "light2", "dark1", "dark2"
title:{
text: "Gráfico de contas a pagar do mês"
},
data: [{
type: "column", //change type to bar, line, area, pie, etc
dataPoints: data
}]
});
chart.render();
},
error: function(data) {
console.log("Error");
}
});
}
Inside the ajax>success I'm successfully getting the data I want, but I can't get the right value for 'res'. My console output is currently: 201912 202001 202001 202001, but I'm trying to understand why the first and second values are different since they are in the same loop.

It's beeen a long time since I've used jquery, however:
$.ajax() is an async function, which means it just makes the request and keeps going, it doesn't wait for the response, which is why you need to specify your code inside the "success" callback.
If you want your "res" variable to update synchronously, you should make the async request using a polling function.
Make the request, wait for the response, increase your counter and call the function again.
Here's an example:
let i = 0;
(function poll(){
var mes = dtIni.addMonths(i);
var ano = mes.getFullYear();
mes = mes.getMonth()+1;
mes = (mes<10 ? '0' : '') + mes;
var res = ano + mes;
console.log(res);
$.ajax({
url: "getMesGrafico.php",
type: "GET",
dataType: "json",
data: {"m": mes},
success: function(data) {
console.log(res);
var chart = new CanvasJS.Chart("body"+res, {
animationEnabled: true,
theme: "light1", // "light1", "light2", "dark1", "dark2"
title:{
text: "Gráfico de contas a pagar do mês"
},
data: [{
type: "column", //change type to bar, line, area, pie, etc
dataPoints: data
}]
});
chart.render();
//once the request is done, increase "i" and call poll() again
i++;
if(i < nMeses)
poll();
},
error: function(data) {
console.log("Error");
}
});
})();

Related

How to properly code Javascript / Ajax for use with Chart.js

I have a controller action in my MVC project that creates a json record with the components needed. This is working. The issue I am having is bringing it into a chart.js canvas. This will be a pie chart that shows all the related countries with a count of each. Json has this info. Originally this was setup to use google visualization but I want to use chart.js. I just started using it. Creating charts with static data is no issue but I am pulling the info from a SQL table and creating a json to read from.
I have tried using the same structure and calling the data: data[] but it doesn't work I have also tried data: getData, which is a var for the ajax function. I am getting the data per the council on refresh.
Here is my controller Action
public ActionResult CustomersByCountry()
{
CustomerEntities _context = new CustomerEntities();
var customerByCountry = (from c in _context.Addresses
group c by c.Country into g
orderby g.Count() descending
select new
{
Country = g.Key,
CountCustomer = g.Count()
}).ToList();
return Json(new { result = customerByCountry }, JsonRequestBehavior.AllowGet);
}
And here is the JavaScript/ajax - which is nested in a document.ready function with the rest of the charts.
EDIT - changed Ajax - Still not working
OrdersByCountry()
function OrdersByCountry() {
$.ajax({
url: '/admin/CustomersByCountry',
method: "GET",
dataType: "json",
error: function (_, err) {
console.log(_, err)
},
success: function (data) {
console.log (data);
var customer = $("#customerByCountryPieChart").get(0).getContext("2d");
console.log(customer)
var cpieChart = new Chart(customer, {
type: 'pie',
data: data,
options: {
responsive: true,
title: {
display: true,
text: "Customers By Country",
}
}
});
}
});
};
Edit - The now working code is below.
I changed it to get states instead of country, just to clear up possible confusion. It made more sense to me to get States rather than Country at this point. This is working - meaning displaying the graph, I still need to work on the labels etc.
OrdersByStates()
function OrdersByStates() {
$.ajax({
url: '#Url.Action("CustomersByStates", "Admin")',
data: JSON,
contentType: "application/json; charset=utf-8",
method: "get",
dataType: "json",
error: function (_, err) {
console.log(_, err)
},
success: function (response) {
console.log(response);
var jsonresult = response
var labels = jsonresult.result.map(function (e) {
return e.State;
});
var data = jsonresult.result.map(function (e) {
return e.CountCustomer;
});;
var ctx = document.getElementById("CustomerByStatePieChart").getContext("2d");
var cpieChart = new Chart(ctx, {
type: 'pie',
data:
{
datasets: [
{
backgroundColor: ["#46BFBD", "#F7464A"],
hoverBackgroundColor: ["#5AD3D1", "#FF5A5E"],
label: "Orders",
data: data,
}]
},
options: {
responsive: true,
title: {
display: true,
text: "Customers By Country",
}
}
});
}
});
};
});
try:
var cpieChart = new Chart(customer, {
type: 'pie',
data: data.result,
options: {
responsive: true,
title: {
display: true,
text: "Customers By Country",
}
}
});
the response from the server "data" var on your request is {result: LIST}

Bootstrap-table : multiple tables , one function

I am on an custom ajax implementation for bootstrap-table (the documentation : http://bootstrap-table.wenzhixin.net.cn/documentation/) :
For some reason, I would like to have multiple bootstrap Tables (let's call them searchTable1 , searchTable2,etc). Each of these table will be set on a custom date range (30 last days, 60 last days,etc).
I would like to pass a parameter (like the table Jquery selector or any data-myCustomDataAttribute parameter) . How can I do that ? (I tried using call but bootstrap already call it on the ajaxCallback function so It seems I cannot use it here).
It will look like stupid to make x functions that are exactly the same except for two fields depending on the table. Does someone has an idea to do that ?
Here is my code :
$('#searchTable').bootstrapTable({
columns: [{
field: 'product',
title: 'Produit'
} , {
field: 'language',
title: 'Langue'
}, {
field: 'comment',
title: 'Commentaire'
}],
showRefresh: true,
ajax: provideFeedbacksList,
cache: false,
dataField: 'feedbacks',
totalField: 'total_size',
search: false,
sidePagination: 'server',
pagination: true
});
The ajax provider :
// I only used this example : http://issues.wenzhixin.net.cn/bootstrap-table/index.html#options/custom-ajax.html
function provideFeedbacksList(params) {
let tableData = params.data;
let serverCall = {};
// add limits and offset provided by bootstrap table
serverCall["page_offset"] = tableData.offset;
serverCall["page_size"] = tableData.limit;
// retrieve the date range for this table :
// will be easy If something like this was possible : params.jquerySelector.attr("date-range-start")
// will be easy If something like this was possible : params.jquerySelector.attr("date-range-end")
let json = JSON.stringify(serverCall);
$.ajax({
url: baseUri + "/feedbacks",
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
data: json,
success: function (reponse) {
params.success(reponse);
},
error: function (er) {
params.error(er);
}
});
}
Bonus, the call stack :
Finally found my answer , I have to wrapper it as a function to enable bootstrap table to pass also its data:
Self solved my issue :
js:
function callbacker(test){
console.log(test);
return function (params) {
console.log(params);
console.log(test);
let tableData = params.data;
let serverCall = {};
// add limits and offset provided by bootstrap table
serverCall["page_offset"] = tableData.offset;
serverCall["page_size"] = tableData.limit;
let json = JSON.stringify(serverCall);
$.ajax({
url: baseUri + "/feedbacks",
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
data: json,
success: function (reponse) {
params.success(reponse);
},
error: function (er) {
params.error(er);
}
});
}
}
html:
$('#searchTable').bootstrapTable({
columns: [{
field: 'product',
title: 'Produit'
} , {
field: 'language',
title: 'Langue'
}, {
field: 'comment',
title: 'Commentaire'
}],
showRefresh: true,
ajax: callbacker("whatEverValueYouWant"),
cache: false,
dataField: 'feedbacks',
totalField: 'total_size',
search: false,
sidePagination: 'server',
pagination: true
});

Redraw Morris Donut after AJAX call

I'm using Morris Donut for a dashboard I'm working on and retrieving data via AJAX using two date ranges as parameters. The problem I'm facing is when I enter two new date ranges the Donut Chart renders a new one on top of Donut already created upon page load. I've searched about and can see information on using setData(), but I have no idea how to include this within my code.
My Code:
$(document).ready(function () {
var start = $('#SearchStart').val();
var end = $('#SearchEnd').val();
populateDonut(start, end);
});
The search button does the following when clicked:
$('#DateRange').click(function() {
var start = $('#SearchStart').val();
var end = $('#SearchEnd').val();
populateDonut(start, end);
});
Here is the function that is called.
function populateDonut(start, end) {
var param = { start: start, end: end };
$.ajax({
type: "POST",
url: "/WebService.asmx/getDonutData",
contentType: "application/json; charset=utf-8",
dataType: 'json',
async: true,
data: JSON.stringify(param),
success: function (result) {
var data = eval("(" + result.d + ")");
var pieChart = '';
if (data.status == 0) {
var donut = Morris.Donut({
element: 'pieChart',
data: [
{ label: "Inbound", value: data.inbound },
{ label: "Outbound", value: data.outbound },
{ label: "Unanswered", value: data.unanswered }
],
colors: ['#1ca8dd', '#33b86c', '#ebc142'],
resize: true,
formatter: function (x) { return x + "%" }
});
}
}
});
}
Screenshot of what is happening after entering new date ranges:
Try calling $("#pieChart").empty(); before rendering the second chart.
Preferably in here:
$('#DateRange').click(function() {
var start = $('#SearchStart').val();
var end = $('#SearchEnd').val();
// Clear the existing chart before populating new donut
$("#pieChart").empty();
populateDonut(start, end);
});
I tried the below code and it's working with me :
$("#chart-id").empty();
You can use it on each time you call chart data .

Display data from json array using ajax

I have the following code on index page the script contains part of the code that will call the data from test page
<div class="leftbox" id="proddisplay">
</div>
var onSubmit = function(e) {
var txtbox = $('#txt').val();
var hiddenTxt = $('#hidden').val();
$.ajax({
type: 'post',
url: 'test.php',
data: {
txt: txtbox,
hidden: hiddenTxt
},
cache: false,
success: function(returndata) {
$('#proddisplay').html(returndata);
console.log(returndata);
},
error: function() {
console.error('Failed to process ajax !');
}
});
};
From test.php i am getting json array that looks like this
[1,2,"text","text2"]
I want to display the json array data in a tabular form and display it inside the div. the view of table should be something like this (it will have some css of its own)
static text: 1
static text: 2
static text: text
static text: text2
static text will be given by me and remains the same throughout however the values of array would change. can anyone tell how i can do so
individually i can display the data from json, but here i also need to put json data in a table and then put that table within a div
First of all you need to encode the array in php before sending to frontend, use json_encode() and then decode it in the success function using JSON.parse() . After just run a loop throught the array.
var onSubmit = function(e) {
var txtbox = $('#txt').val();
var hiddenTxt = $('#hidden').val();
$.ajax({
type: 'post',
url: 'test.php',
data: {
txt: txtbox,
hidden: hiddenTxt
},
cache: false,
success: function(returndata) {
var returneddata = JSON.parse(returndata);
var htmlData= '';
for(var i=0; i<returneddata.length; i++){
htmlData+= 'static text: '+returneddata[i]+' <br>';
}
$('#proddisplay').html(htmlData);
console.log(returndata);
},
error: function() {
console.error('Failed to process ajax !');
}
});

Jquery display message while php processing

I'm using jQuery ajax call to post process a form.
I want to display a loading message or image while the form is processed and when the action is completed to display a complete message.
How can I do it?
This is my jQuery code.
$s('body').on('click', '#group-update', function() {
var formInputs = $s('input').serializeArray();
var groupId = $s(this).data('group');
var error = $s('#modal .info');
var tr = $s('#dataT-attrgroup').find('tr.on_update');
formInputs.push({
name: 'id',
value: groupId
});
$s.ajax({
type: 'post',
url: 'index.php?controller=attribute&method=updateGroup',
data: formInputs,
dataType: 'JSON',
success: function(data) {
if(data.response === false){
error.addClass('info-error');
error.html(data.message);
}else{
oTable.row(tr).data(data).draw();
$s('#modal').modal('hide');
tr.removeClass('on_update');
$s.growl.notice({
title: 'Success',
message: 'Grupul de atribute a fost actualizat'
});
}
}
});
});
Before ajax function display your loader and inside the success function from your ajax hide it.
As you can see in my example i inserted $('.loader').show(); and $('.loader').hide();
$('.loader').show();
$s.ajax({
type: 'post',
url: 'index.php?controller=attribute&method=updateGroup',
data: formInputs,
dataType: 'JSON',
success: function(data) {
if(data.response === false){
error.addClass('info-error');
error.html(data.message);
}else{
oTable.row(tr).data(data).draw();
$s('#modal').modal('hide');
tr.removeClass('on_update');
$s.growl.notice({
title: 'Success',
message: 'Grupul de atribute a fost actualizat'
});
}
$('.loader').hide();
}
});
According to the PHP docs:
The upload progress will be available in the $_SESSION superglobal when an upload is in progress, and when POSTing a variable of the same name as the session.upload_progress.name INI setting is set to. When PHP detects such POST requests, it will populate an array in the $_SESSION, where the index is a concatenated value of the session.upload_progress.prefix and session.upload_progress.name INI options. The key is typically retrieved by reading these INI settings, i.e.
You should take a look at : https://github.com/blueimp/jQuery-File-Upload/wiki/PHP-Session-Upload-Progress
I think this will definitely help you out!
Display your message just before launching $.ajax();
And close it in the success (and error) callback functions.
example :
$s('body').on('click', '#group-update', function() {
var formInputs = $s('input').serializeArray();
var groupId = $s(this).data('group');
var error = $s('#modal .info');
var tr = $s('#dataT-attrgroup').find('tr.on_update');
formInputs.push({
name: 'id',
value: groupId
});
var dlg = $s('<div/>').text('your message').dialog();
$s.ajax({
type: 'post',
url: 'index.php?controller=attribute&method=updateGroup',
data: formInputs,
dataType: 'JSON',
error:function() {
dlg.dialog('close');
},
success: function(data) {
dlg.dialog('close');
if(data.response === false){
error.addClass('info-error');
error.html(data.message);
}else{
oTable.row(tr).data(data).draw();
$s('#modal').modal('hide');
tr.removeClass('on_update');
$s.growl.notice({
title: 'Success',
message: 'Grupul de atribute a fost actualizat'
});
}
}
});
});
If you go through ajax section of jquery documentation you will notice some more method like success ie error, beforesend, complete etc. Here is the code snippet.
$s.ajax({
type: 'post',
url: 'index.php?controller=attribute&method=updateGroup',
data: formInputs,
dataType: 'JSON',
beforeSend : function(){
// load message or image
},
success: function(data) {
// write code as per requirement
},
complete : function(){
// load complete message where you previously added the message or image, as a result previous one will be overwritten
}
});

Categories