jquery ajax nested callbacks - javascript

I have nested callabcks but resulted output is not ordered correctly. My ajax results are in ascending orders of id but html generated is random. can someone help me out pls?
var formatedhtml = '';
$.ajax({
type: "POST",
url: BASE_URL + 'index.php/orders/read',
dataType: 'json',
success: function(data) {
$.each(data, function(key, value) {
console.log(value);
getdetails(value['id'], function(output) {
formatedhtml = formatedhtml +
'<div class="col-md-4 col-sm-4 col-lg-3 col-xs-6">' +
' <div class="row">' +
' <div class="orderno">' + value['id'] + '</div>' +
'<div class="tableno">' + value['tableno'] + '</div>' +
'<div class="ordertype">' + value['type'] + '</div>' +
'<div class="timestamp">' + value['created'] + '</div>' +
' </div>' +
'<hr>';
$.each(JSON.parse(output['items']), function(k, val) {
formatedhtml = formatedhtml + '<div class="row">' +
'<div class="quantity">' + val[3] + '</div>' +
'<div class="item">' + '</div>' +
'</div>';
});
formatedhtml = formatedhtml +
'<div class="row">' +
'<div class="notes">' + value['id'] + '</div>' +
'</div>' +
'</div>';
$("#orderlist").html(formatedhtml);
console.log(output);
});
});
}
});
edit:
Here is getdetails function. its an ajax request.
function getdetails(id, callback) {
var result;
$.ajax({
type: "POST",
url: BASE_URL + 'index.php/orders/readdetails',
dataType: 'json',
data: {
id: id,
},
success: function(data) {
callback(data[0]);
}
});
};

There are a lot of ways to achieve this, one is to use a promise and sort by id when all requests are done. Another you could create the template and append the details on callback as each detail request has an id you can define in your template a class like 'id-'+value['id'] and use jquery selector and append detail template.
Another solution would be to create a function loop that calls itself untill orderCount == orderLoaded.
Job is done synchronously (takes more time)
//Mock ajax function
$.ajax = function (param) {
if(param.url.indexOf('readdetails') != -1){
param.success(itemsData);
} else {
param.success(ordersData);
}
};
//Mock data
var ordersData = [
{ id : 1, tableno : 'xyz', type: 'invoice', created: '01/01/2001' },
{ id : 2, tableno : 'xyz', type: 'invoice', created: '01/01/2001' },
{ id : 3, tableno : 'xyz', type: 'invoice', created: '01/01/2001' }
];
var itemsData = [
{ id : 1, orderid: 1, quantity: 5 },
{ id : 2, orderid: 1, quantity: 2 },
{ id : 3, orderid: 1, quantity: 1 }
];
// Globals
var formatedhtml = [];
var orders = [];
var lastOrderLoaded = 0;
var BASE_URL = 'localhost/';
function tpl(order, items) {
var html = '<tr class="col-md-4 col-sm-4 col-lg-3 col-xs-6">' +
' <td class="orderno">' + order['id'] + '</td>' +
'<td class="tableno">' + order['tableno'] + '</td>' +
'<td class="ordertype">' + order['type'] + '</td>' +
'<td class="timestamp">' + order['created'] + '</td>' +
' </tr>';
$.each(items, function(key, item) {
html += '<tr class="row">' +
'<td class="item">item: ' + item.id + '</td>' +
'<td class="quantity">quantity: ' + item.quantity + '</td>' +
'</tr>';
});
html +=
'<tr class="row">' +
'<td class="notes"> notes </td>' +
'<td class="notes"> order id ' + order['id'] + '</td>' +
'</tr>' +
'</tr>';
formatedhtml.push({ id: order.id, html : html });
}
$.ajax({
type: "POST",
url: BASE_URL + 'index.php/orders/read',
dataType: 'json',
success: function(data) {
lastOrderLoaded = 0;
orders = data;
getdetails(orders[0]);
}
});
function getdetails(order) {
$.ajax({
type: "POST",
url: BASE_URL + 'index.php/orders/readdetails',
dataType: 'json',
data: {
id: order.id,
},
success: function(data) {
tpl(order, data);
if(lastOrderLoaded < orders.length - 1){
lastOrderLoaded++;
getdetails(orders[lastOrderLoaded]);
} else {
formatedhtml.forEach(function(element){
$("#orderlist").append(element.html);
}); // end each
}
}
});
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="orderlist" border="1">
<tr><th>id</th><th>no</th><th>type</th><th>date</th></tr>
</table>
Promise Solution:
Job is done asynchronously (might take less time also bombards the server with many requests at once)
var formatedhtml = [];
function tpl(order, items) {
var html = '<div class="col-md-4 col-sm-4 col-lg-3 col-xs-6">' +
' <div class="row">' +
' <div class="orderno">' + order['id'] + '</div>' +
'<div class="tableno">' + order['tableno'] + '</div>' +
'<div class="ordertype">' + order['type'] + '</div>' +
'<div class="timestamp">' + order['created'] + '</div>' +
' </div>' +
'<hr>';
$.each(JSON.parse(items['items']), function(key, item) {
var html += '<div class="row">' +
'<div class="quantity">' + item[3] + '</div>' +
'<div class="item">' + '</div>' +
'</div>';
});
html +=
'<div class="row">' +
'<div class="notes">' + order['id'] + '</div>' +
'</div>' +
'</div>';
formatedhtml.push({ id: order.id, html : html });
}
$.ajax({
type: "POST",
url: BASE_URL + 'index.php/orders/read',
dataType: 'json',
success: function(data) {
var syncLoad = [];
$.each(data, function(key, value) {
syncLoad.push(getdetails(value, tpl));
});
$.when.apply($, syncLoad).done(function() {
formatedhtml.sort(function(a, b){
return a.id - b.id;
});
formatedhtml.forEach(function(element){
$("#orderlist").append(element.html);
});
});
}
});
function getdetails(order, callback) {
return $.ajax({
type: "POST",
url: BASE_URL + 'index.php/orders/readdetails',
dataType: 'json',
data: {
id: order.id,
},
success: function(data) {
callback(order, data[0]);
}
});
};

Use async:false in your getDetails() ajax call.
function getdetails(id, callback) {
var result;
$.ajax({
type: "POST",
url: BASE_URL + 'index.php/orders/readdetails',
dataType: 'json',
async: false,
data: {
id: id,
},
success: function (data) {
callback(data[0]);
}
});

Related

How do I call Datatables draw() method in Ajax?

I am trying to implement datatables draw() method in my Django application using AJAX. I have implemented both datatables and AJAX, which are working fine. However, I am facing a lot of challenges anytime I create a new object and call the draw() method so that datatables can refresh the table and show the newly created data the proper way. If I add the draw() method, the table does not get populated at all except I refresh the page.
main.js
//datatables
$(document).ready(function() {
$('table').on('click', ".dropdownDatatableButton" ,function() {
$( this ).toggleClass( "active");
});
function csrfSafeMethod(method) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
};
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
var table = $('#boardsTable').DataTable({
"autoWidth": false,
"info": false,
"lengthChange": false,
"processing": true,
"hover": true,
"serverMethod": 'post',
"searching": true,
"ajax": "/boards/api/data/?format=datatables",
"pagingType": "full_numbers",
"order": [[ 0, "asc" ]],
language: {
search: "",
"zeroRecords": '<img class=' + '"dataTables-error-image"' + 'src=' + "'/static/media/images/empty-search.jpg'"
+ '/>' + '<p class=' + '"dataTables-error-text"' + '>'
+ 'No boards were found that match your search' + '<p/>',
"loadingRecords": '<div class="spinner-border m-5" role="status">'
+ '<span class="sr-only d-block">Loading...</span> </div>'
+ '<p class="d-block text-center mt-3">Pulling board information...' + '</p>',
"processing": '<p class="d-block text-center datatables-processing-text">Please wait...' + '</p>',
"emptyTable": '<img class=' + '"dataTables-error-image"' + 'src=' + "'/static/media/images/new.jpg'"
+ '/>' + '<p class=' + '"dataTables-error-text font-weight-bold"' + '>'
+ 'No boards to show right now' + '<p/>'
+ '<p class=' + '"dataTables-empty-table-description"' + '>'
+ 'When you start working on recruitment campaigns, we’ll list all your boards here.'
+ '<p/>'
+ '<a class="dataTables-error-create-btn show-only-on-mobile" data-bs-toggle="modal"'
+ 'data-bs-target="#createBoardModal" data-bs-backdrop="static"'
+ 'data-bs-keyboard="false">' + 'Create a board' + '<a/>',
},
initComplete : function() {
$("#boardsTable_filter").detach().appendTo('.filter-form');
},
"drawCallback": function(settings) {
var pagination = $(this).closest('.dataTables_wrapper').find('.dataTables_paginate');
pagination.toggle(this.api().page.info().pages > 1);
},
"columns": [
{data: null,
render: function ( data, type, row ) {
// show the board avatar and make merge it with `data: name`
return '<a class="datatable-board-link" href="' + data.url.toLowerCase() + '/manage' + '">'
+ '<img class="datatable-board-link-img" ' + 'src="' + data.avatar + '" ' + 'width="30px" '
+ 'height="30px" ' + 'alt="board avatar" />' + data.name + '</a>' ;
}
},
{data: null,
render: function ( data, type, row, meta ) {
// show the URL which are accessible to candidates
return '<a class="new-tab-board-link" href="' + data.lead.username + '/'
+ data.url + '" target="_blank">' + '/' + data.url
+ '<span class="material-icons">open_in_new</span>' + '</a>';
}
},
{ data: "lead",
render: function ( data, type, row, meta ) {
// show the lead recruiter avatar and combine the first and last names into a single table field
return '<a class="datatable-profile-link"' + 'href="'
+ 'http://127.0.0.1:8080/people/teams/' + data.id + '/' + data.username.toLowerCase() +'"'
+ 'target="_blank"' + '>' + '<img class="datatable-profile-link-img" ' + 'src="'+ data.avatar
+ '" ' + 'width="30px" ' + 'height="30px" ' + 'alt="' + data.name + ' ' + "'s avatar" + '"'
+ '/>' + data.name + '</a>';
},
},
{ data: null,
render: function ( data, type, row, meta ) {
return '<div class="dropdown datatables-dropdown" id="datatablesDropdown">'
+ '<span class="material-icons btn dropdownDatatableButton" id="dropdownDatatableButton"'
+ 'type="button"' + 'data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">'
+ 'more_horiz</span>'
+ '<div class="dropdown-menu dropdown-menu-right datatables-dropdown-inner"'
+ ' aria-labelledby="dropdownDatatableButton">'
+ '<ul>'
+ '<li>Board settings</li>'
+ '<li><a class="btn btn-link btn-sm text-left">Delete</a></li>'
+ '</ul>'
+ '</div>'
+ '</div>';
},
},
],
"columnDefs": [
{"width": "10%", "targets": 3, "orderable": false},
],
});
table.columns().iterator('column', function (ctx, idx) {
$(table.column(idx).header()).append('<span class="sort-icon"/>');
});
// call the AJAX post method
$("#createBoardViaModalForm").on('submit', function (e) {
var spinner = $('#loader');
for ( instance in CKEDITOR.instances ) {
CKEDITOR.instances[instance].updateElement();
}
e.preventDefault();
spinner.show();
var serializedData = $(this).serialize();
$.ajax({
type: 'POST',
url: "post/ajax/board/",
data: serializedData,
success: function (data) {
if($('input[type="checkbox"]').prop("checked") == true){
//some codes
...
//take some serialised data and populate the table
// THIS IS WHERE THE ISSUE STARTS
var data = JSON.parse(data["data"]);
var fields = data[0]["fields"];
$("#boardsTable tbody").prepend(
`<tr>
<td>${fields["name"]||""}</td>
<td>${fields["url"]||""}</td>
<td>${fields["lead"]||""}</td>
</tr>`
);
// invoke datables draw() method to refresh the table
table.draw();
setTimeout(function(){
spinner.hide();
}, 1000);
console.log("Checkbox is checked. Modal will not be closed");
}
else if($('input[type="checkbox"]').prop("checked") == false){
// some codes
...
table.draw();
// more codes
}
},
error: function (jqXHR, textStatus, errorText) {
let data = jqXHR.responseJSON;
// more codes
console.log('There are some errors on the submitted form. Check the data errors array')
console.log(data)
}
})
});
//clear up the error logs when a user enters a value in the highlighted input field
});
I used the datatables reload API.
table = $("#boardsTable").DataTable().ajax.reload();
In your AJAX success function, you can draw it like so:
success: function(data) {
console.log(data);
if (data.d != null && data.d != undefined && data.d.results.length > 0) {
var table = $('#boardsTable').DataTable();
table.rows.add(data.d.results).draw();
}
}

Codigniter Javascript nested Jquery error

My requirnment is if data1[count1].result_type > 0 then the td will be a drop down list from a datatable. Nut is i try this, the output is like this, all the required options are comming to a single selectbox insted of the relevent row. And the result comes to the very last row.
The desired result would be two dropdowns at the last two rows. The wanted result options all together in the one dropdown. How can I solve this?
$('#bill_no_search').click(function() {
{
$("#data_table_one tbody").html("");
var barcode = $('#barcode_no').val();
$.ajax({
url: "<?php echo base_url('index.php/Lab_and_lab_office/get_barcode_to_bill_no'); ?>",
data: {
barcode: barcode
},
method: "POST",
dataType: "JSON",
success: function(data) {
var bill_no = data.bill_no;
console.log(bill_no)
$.ajax({
url: "<?php echo base_url('index.php/Lab_and_lab_office/resulting'); ?>",
data: {
bill_no: bill_no
},
method: "POST",
dataType: "JSON",
success: function(data) {
for (var count = 0; count < data.length; count++) {
var element_id = data[count].element_id;
var ct = 'screen' + count + '';
var bt = 'td' + count + ''
var result = 'result' + count + ''
$('#data_table_one tbody').append(
'<tr>' +
'<td >' + (count + 1) + '</td>' +
'<td >' + data[count].billing_element_result_id + '</td>' +
'<td >' + data[count].bill_no + '</td>' +
'<td >' + data[count].processor_id + '</td>' +
'<td >' + data[count].test_processor_display_name + '</td>' +
'<td >' + data[count].test_code + '</td>' +
'<td >' + data[count].test_details + '</td>' +
'<td contenteditable=true id="result' + count + '">' + data[count].result + '</td>' +
'<td id="td' + count + '" contenteditable=true><select id="screen' + count + '" style="display:none"></select></td>' +
'<td contenteditable=true id="resultcell">' + data[count].result + '</td>' +
'</tr>'
);
console.log(ct)
$.ajax({
url: "<?php echo base_url('index.php/Lab_and_lab_office/get_result_type'); ?>",
data: {
element_id: element_id
},
method: "POST",
dataType: "JSON",
success: function(data1) {
for (var count1 = 0; count1 < data1.length; count1++) {
if (data1[count1].result_type > 0) {
document.getElementById(ct).style.display = "block";
$('#' + ct + '').append(
'<option>' + data1[count1].result_options + '</option>'
);
document.getElementById(bt).contentEditable = "false";
document.getElementById(result).contentEditable = "false";
}
console.log(ct)
}
}
})
}
}
})
}
})
}
})

unexpected end of input error while passing json data from a JS each loop to a JS function

I have a jquery foreach appended list in a table. What I want is to pass the full object that I am getting from an ajax success function. But when I try to pass the Object as a parameter to a different JS function, the parameter gets unexpected end of input.
This is my appended table:
$.ajax({
type: "post",
url: "#Url.Content("~/Estimate/GetOffsetLetterHeadCost")",
data: $('#OffLetterHeadForm').serialize(),
datatype: "json",
traditional: true,
success: function(data) {
var Json = data;
$.each(Json, function(index, obj) {
var row = '<tr>' + '<td><b>' + obj.VendorName + '</b></td>'
+ '<td><label id="machineId' + index + '">'
+ obj.MachineName + ' </label></td>'
+ '<td><input type="button" value="Order" id="btn'
+ index + '"onclick="SaveOffsetOrder('
+ JSON.stringify(obj) + ')"/></td></tr>';
$("#AllVendorsList").append(row);
});
}
});
<table id="AllVendorsList"></table>
function SaveOffsetOrder(obj) {
// do something with obj
}
At input close I am getting unexpexted end of input. Please help. I am new to javascript
enter image description here
Problem is that JSON.stringify(obj) doesn't escape quotes like this \" and the result is invalid html.
I suggest using jQuery onclick binding, so you don't have to stringify obj and then parse it.
Solution: https://jsfiddle.net/xpvt214o/452188/
var Json = [{
VendorName: 'kia',
MachineName: 'ceed'
}, {
VendorName: 'dacia',
MachineName: 'logan'
}];
$.each(Json, function(index, obj) {
var row = '<tr>' + '<td> <b>' + obj.VendorName + '</b></td>' + '<td><label id="machineId' + index + '">' + obj.MachineName + '</label></td>' + '<td><input type="button" value="Order" id="btn' + index + '"/></td></tr >';
$("#AllVendorsList").append(row);
$("#btn" + index).on('click', $.proxy(SaveOffsetOrder, this, obj));
});
function SaveOffsetOrder(obj) {
console.info(obj);
}
<table id="AllVendorsList"></table>
there are a lot of syntax problem. First of all, It's not clear where you have putted your js functions. If it's an .html file, your code should be:
<table id="AllVendorsList"></table>
<script type="text/javascript">
$.ajax({
type: "post",
url: "#Url.Content("~/Estimate/GetOffsetLetterHeadCost
")",
data: $('#OffLetterHeadForm').serialize(),
datatype: "json",
traditional: true,
success: function(data) {
var Json = data;
$.each(Json, function(index, obj) {
var row = '<tr>' + '<td> <b>' + obj.VendorName + '</b> </td> ' +
'<td><label id="machineId' + index + '">' + obj.MachineName + '
< / label > < /td > ' + '<td> <input type="button" value="Order"
id="btn' + index + '"onclick ="SaveOffsetOrder(' +
JSON.stringify(obj) + ')" / > < /td></tr > ';
$("#AllVendorsList").append(row);
});
}
});
function SaveOffsetOrder(obj) {
// do something with obj
}
</script>
So your error is related to syntax problems.

How to call a thymeleaf modal fragment from a javascript generated link?

I have a javascript function that renders a table from an ajax call.
The row rendering bit is:
function buildTable(id) {
trHTML = null;
$.ajax({
type: "GET",
url: siteroot + "apiURL" + id,
data: {},
dataType: "json",
cache: false,
success: function (data) {
for (i = 0; i < data.length; i++) {
trHTML +=
'<tr>' +
'<td>' + data[i].value +
'<a class="pull-right" href="#" data-toggle="modal" data-target="#edit-modal" > ' +
'<span class="pull-right glyphicon glyphicon-pencil"></span>' +
'</a>' +
'</td>' +
'<td>' + data[i].text + '</td>' +
'<td>' + data[i].description + '</td>' +
'</tr>';
}
$('#resourceTable').append('<tbody>' + trHTML + '</tbody>');
},
error: function (msg) {
alert(msg.responseText);
}
});
}
And the modal is defined as:
<div th:replace="../../modals/modal"></div>
The issue I am facing is that the link is here on the rendered table, but when I click it, the modal does not come on.
What am I not seeing here?

Selectize (.js) and external source

How I can load dynamicly (like $.ajax or getjson) in selectize options list?
Searched thru the forum, looks like nobody did it this way for some reason (?)
Thanks.
The load(fn) method is probably what you are looking for.
Loads options by invoking the the provided function. The function
should accept one argument (callback) and invoke the callback with the
results once they are available.
Here is the first Remote Source example:
$('#select-repo').selectize({
valueField: 'url',
labelField: 'name',
searchField: 'name',
create: false,
render: {
option: function(item, escape) {
return '<div>' +
'<span class="title">' +
'<span class="name"><i class="icon ' + (item.fork ? 'fork' : 'source') + '"></i>' + escape(item.name) + '</span>' +
'<span class="by">' + escape(item.username) + '</span>' +
'</span>' +
'<span class="description">' + escape(item.description) + '</span>' +
'<ul class="meta">' +
(item.language ? '<li class="language">' + escape(item.language) + '</li>' : '') +
'<li class="watchers"><span>' + escape(item.watchers) + '</span> watchers</li>' +
'<li class="forks"><span>' + escape(item.forks) + '</span> forks</li>' +
'</ul>' +
'</div>';
}
},
score: function(search) {
var score = this.getScoreFunction(search);
return function(item) {
return score(item) * (1 + Math.min(item.watchers / 100, 1));
};
},
load: function(query, callback) {
if (!query.length) return callback();
$.ajax({
url: 'https://api.github.com/legacy/repos/search/' + encodeURIComponent(query),
type: 'GET',
error: function() {
callback();
},
success: function(res) {
callback(res.repositories.slice(0, 10));
}
});
}
});

Categories