jQuery - Do action when all ajax have completed - javascript

I've read about the jQuery's Deferred object, but I can't seem to make much sense out of it, here's my problem, I've got the following code:
function preprocess(form) {
$(form).find(".input input").each(function() {
var required = $(this).attr("required");
var checkField = $(this).closest(".inputcontainer").children(".check");
var errorField = $(this).closest(".inputcontainer").children(".errormessage");
if (typeof required !== 'undefined') {
$(checkField).each(function() {
$(this).css("color", "#FFFF00");
$(this).html("✘");
});
$(errorField).each(function() {
$(this).css("color", "#FFFF00");
$(this).html("(Required)");
});
}
else {
$(checkField).each(function() {
$(this).css("color", "#FFFF00");
$(this).html("✔");
});
$(errorField).each(function() {
$(this).css("color", "#000000");
$(this).html("");
});
}
});
$(form).find("datalist").each(function() {
var datalist = $(this);
callService({
name: "datalist_" + $(this).attr("id"),
data: { },
success: function(json) {
$(json).each(function() {
var html = "";
$(this.options).each(function() {
html += "<option value='" + this.value + "'>";
});
$(datalist).append(html);
});
}
});
});
$(form).find("select").each(function() {
var select = $(this);
callService({
name: "select_" + $(this).attr("name"),
data: { },
success: function(json) {
$(json).each(function() {
var html = "";
$(this.options).each(function() {
html += "<option value='" + this.id + "'>" + this.value + "</option>";
});
$(select).append(html);
});
}
});
});
}
This code prepares a form to be ready to be presented to the user, which involves AJAX calls, which I have wrapped in a callService({}); call, what you can see is the following:
It checks input and puts possibly (Required) next to the fields. (No AJAX)
It loads options from <datalist> and <select>s dynamically. (AJAX)
Then I also have the following (simplified):
function setContent(html, url) {
html = $.parseHTML(html);
$(html).filter("form").each(function() {
preprocess($(this));
});
$("#pagemain").html(html);
}
This gets html from an AJAX call, then calls preprocess on all its forms and updates the #pagemain.
However now data is being displayed before the preprocess has completely finished.
The question: How can I do the $("#pagemain").html(html); after preprocessed ánd involving AJAX processes, have been finished?

Try:
function preprocess(form) {
//Your above code is omitted for brevity
var promises = [];
$(form).find("datalist").each(function() {
var defered = $.Deferred();//create a defered object
promises.push(defered.promise());//store the promise to the list to be resolved later
var datalist = $(this);
callService({
name: "datalist_" + $(this).attr("id"),
data: { },
success: function(json) {
$(json).each(function() {
var html = "";
$(this.options).each(function() {
html += "<option value='" + this.value + "'>";
});
$(datalist).append(html);
});
defered.resolve();//resolve the defered when ajax call has finished
}
});
});
$(form).find("select").each(function() {
var defered = $.Deferred();//create a defered object
promises.push(defered.promise());//store the promise to the list to be resolved later
var select = $(this);
callService({
name: "select_" + $(this).attr("name"),
data: { },
success: function(json) {
$(json).each(function() {
var html = "";
$(this.options).each(function() {
html += "<option value='" + this.id + "'>" + this.value + "</option>";
});
$(select).append(html);
});
defered.resolve();//resolve the defered when ajax call has finished
}
});
});
return promises;
}
Your setContent:
function setContent(html, url) {
html = $.parseHTML(html);
var promises = [];
$(html).filter("form").each(function() {
promises = promises.concat(preprocess($(this)));//Concatenating all promises arrays
});
$.when.apply($,promises).then(function(){// Use $.when to execute a function when all deferreds are resolved.
$("#pagemain").html(html);
});
}

Deferred's can be a little intimidating to learn at first, but, like most things, once the light bulb goes on and you get it, it's pretty simple. The simple setup for creating a deferred object is like this:
var defer = $.Deferred(function(dfd) {
// do the processing you need, and then...
// when processing is complete, make a call to...
dfd.resolve(/* return data goes here, if required */);
}).promise();
// use the deferred object like it was an ajax call
defer.then(/* do the stuff that needed to wait */);
So, using your example:
function setContent(html, url) {
html = $.parseHTML(html);
var defer = $.Deferred(function(dfd) {
$(html).filter("form").each(function() {
preprocess($(this));
});
dfd.resolve();
}).promise();
defer.then($("#pagemain").html(html));
}

neat solution will be using when :
http://api.jquery.com/jQuery.when/
$.when( {//your preprocessing function here
} ).done(function( x ) {
//your done action here
});

Related

How to run ajax request in array loop

ok so i am creating a web app and i have run into some issues
first i make a request to an api endpoint this returns a json response i take what i need and ad it into a key value array
i then have to loop through all the items in this array and for each item i need to make a request to a second api endpoint that returns some html
i need to then append this html to an eliment on the page
i need this to be done one after another the issue i have is that the .each() loop finishes instantly while the requests are still on going in the background meaning the aliments are appended to the html eliment on the page way after they should
how can i make the loop wait untill the requests are done and html is appended before moving onto the next item in the array
$("#middlebox").fadeTo(3000, 0, function() {
$("#middlebox").html(LOADING);
});
$("#middlebox").fadeTo(3000, 1, function() {
var API_URL = window.location.href + 'api.php?action=channels&category='+$this.data("text")+'&username='+$("#username").val()+'&password='+$("#password").val();
var CHANNELS = {};
var API_CHANNELS = '<div class="Live">';
$.getJSON(API_URL).done( function( API_RESULT ) {
$.each( API_RESULT.items, function( API_INDEX, API_ITEM ) {
var API_ID = API_ITEM.stream_id;
var API_ICON = API_ITEM.stream_icon;
CHANNELS[API_ID] = API_ICON;
});
}).then( function() {
$.each( CHANNELS, function( CHANNEL_KEY, CHANNEL_VALUE ) {
var EPG_URL = window.location.href + 'api.php?action=epg&id='+CHANNEL_KEY+'&username='+$("#username").val()+'&password='+$("#password").val();
API_CHANNELS += '<div class="channel focusable"><div class="LiveIcon"><img src="' + CHANNEL_VALUE + '" class="TvIcon"></div>';
$.ajax({
url:EPG_URL,
type: 'GET',
dataType: 'html',
success:function(content,code) {
API_CHANNELS += content;
}
});
API_CHANNELS += '</div>';
});
$("#middlebox").fadeTo(3000, 0, function() {
API_CHANNELS += '</div>';
$("#middlebox").html(API_CHANNELS);
$("#middlebox").fadeTo(3000, 1, function() {
});
});
});
});
Ajax calls are asynchronous so you can't use a synchronous loop to process the requests.
You can use Promise.all to wait for all ajax requests and then process replies in a loop.
Promise.all(CHANNELS.map(function( CHANNEL_KEY, CHANNEL_VALUE ) {
var EPG_URL = window.location.href + 'api.php?action=epg&id='+CHANNEL_KEY+'&username='+$("#username").val()+'&password='+$("#password").val();
return $.ajax({
URL: EPG_URL,
type: 'GET',
dataType: 'html'
}).then(function(content) {
return [CHANNEL_KEY, CHANNEL_VALUE, content];
});
})).then(function(channels) {
$.each(channels, function(CHANNEL_KEY, CHANNEL_VALUE, content) {
API_CHANNELS += '<div class="channel focusable"><div class="LiveIcon"><img src="' + CHANNEL_VALUE + '" class="TvIcon"></div>';
API_CHANNELS += content;
API_CHANNELS += '</div>';
});
$("#middlebox").fadeTo(3000, 0, function() {
/* ... */
});
});

event handler are not working in asynchronous ajax call

i am filling up my dropdowns using this ajax call ..selectItems create select option tags in html using attribute_map
var $el = this.$el(model);
var rule_title = "Job Family: ";
var attribute_map = [];
var current_object = this;
$el.append(this.getRuleTitle(rule_title, model));
jQuery.ajax({
url : "<%= Rails.configuration.url_prefix %>/team/index/get_rule_attribute_values",
type : "GET",
data : { name : "jobFamily" },
dataType : "json",
success : function(data){
var attribute_array = data.value.rule_attribute_values;
attribute_array.sort(function(a,b){
if(a.display_name > b.display_name){
return 1;
}
if(a.display_name < b.display_name){
return -1;
}
return 0;
});
var index = 0;
var obj;
for (obj in attribute_array){
attribute_map[index] = [];
attribute_map[index][0] = attribute_array[index].display_name + " ( " + attribute_array[index].internal_name + " ) " ;
attribute_map[index][1] = attribute_array[index].internal_name;
index++;
}
current_object.selectItems($el,
attribute_map,
"jobFamily", model.jobFamily, {multiple : "multiple", "data-placeholder" : "Add Constraint..."}, "400px");
},
complete : function() {
console.log("completed");
},
error : function(jqXHR, textStatus,errorThrown){
var requestResponse = {
httpStatus: jqXHR.status,
error:jqXHR.statusText,
};
}
});
when i put async as false ..event handler works fine but in synchronous call , the just doesn't do anything
event handler looks like
$('.chosen-select jobFamily').on('change',function(evt, params){
console.log("completeddddddd");
var value = $('.chosen-select jobFamily').val();
console.log(value);
if (value == null) {
// Input is empty, so uncheck the box.
$('.jobFamily').prop("checked", false);
} else {
// Make sure the box is checked.
$('.jobFamily').prop("checked", true);
}
});
});
where '.chosen-select jobFamily' is class of select tag and '.jobFamily' is class of check box ... i have tried writing my jquery inside complete argument of ajax call , i tried writing my jquery inside
$('document).bind('ajaxComplete',function({
//above jquery
});
please help . i have spent more than 2 days on that . all code lies inside ready function.

AJAX - Javascript is breaking whenever the AJAX script is called

I hired a developer to help with some work, he was mostly PHP focused and attempted this javascript. The following AJAX script breaks the page whenever it reloads the HTML into the DOM. It called a function via Codenigniter to reload the view within the page. Once this happens, all of the javascript no longer works.
I can't seem to find a solution that helps solve this issue. Please help.
Note: Ideally I would of rather the code only loaded the data and not refresh the HTML, but for now this will need to do as I am up against a timeline.
The code:
$(document).ready(function () {
// Ajax Form Submit
$('body').on('click', '.submitForm', function () {
var formid = $(this).parents('form').attr('id');
var validationResult = $('#' + formid).validationEngine('validate');
if (!validationResult) {
return false;
}
var url = $('#' + formid).attr('action');
var formdata = $('#' + formid).serialize();
if ($('#' + formid).find('.submitForm').hasClass('loading')) {
$(this).hide();
$('#' + formid).find('.loader').show();
}
$.ajax({
type: "POST",
cache: false,
url: url,
data: formdata,
dataType: 'json',
success: function (data) {
if ($('#' + formid).find('.submitForm').hasClass('loading')) {
$('#' + formid).find('.submitForm').css('display', 'inline');
$('#' + formid).find('.loader').hide();
}
if (data.type == 'add') {
if (data.html) {
var newhtml = "<tr>" + data.html + "</tr>";
$('.tab-pane.active table').append(newhtml);
}
$('#' + formid).find('.message').html(data.msg).show();
$('#' + formid).trigger('reset');
setInterval(function () {
$('#' + formid).find('.message').hide();
}, 5000);
} else {
if (data.error) {
$('#' + formid + ' .message').show().html(data.error);
} else {
$('#' + formid + ' .message').show().html(data.msg);
if (data.reload_loc) {
window.setTimeout(function () {
window.location.href = data.reload_loc;
}, 4 * 1000);
}
}
}
}
});
});
// Generic Save Form Data
$('body').on('click', '#saveFormdata', function () {
var formid = $(this).parents('form').attr('id');
var validationResult = $('#' + formid).validationEngine('validate');
if (!validationResult) {
return false;
}
$('#' + formid).submit();
});
});
You just do something like this:
function bindEvent()
{
$('body').on('click', '.submitForm', function () { //Your code });
$('body').on('click', '#saveFormdata', function () { //Your code});
}
function unblindEvent()
{
$('body').off('click', '.submitForm'); //Something like this, please read Jquery.off
$('body').off('click', '#saveFormdata');
}
Before you replace these element, call unblindEvent(). And after you replace these elements call bindEvent().

Callback never called on Jquery.post();

I'm having some trouble using JQUERY Post function.
I have 2 functions that call JQUERY Post function.
Both of them is working fine, but the callback function is never called (handleLike).
When I call handleLike manually, it's works perfect.
(Even if handleLike has just an alert inside, the callback function is not called)
Could you please help me with this thing?
<script type="text/javascript">
$(document).ready(function() {
function handleLike(v_cb){
alert("Call back chamou!");
$('#erro').html(v_cb.mensagem);
if (v_cb.class == 'map'){
var elemento = $('#maplike');
}else{
var elemento = $('#commentlike'+v_cb.id);
}
if (!(elemento.hasClass('disabled'))){
elemento.addClass("disabled");
var likes = elemento.find('font').text();
likes++;
elemento.find('font').html(likes);
}
}
$('#maplike').click(function() {
//var map_id = $('#like').find('font').attr('value');
var id = $(this).attr("name");
if (!($(this).hasClass('disabled'))){
var JSONObject= {
"mensagem":"Testando Json",
"id":86,
"class":"map"
};
handleLike(JSONObject);
alert("Teste");
$.post(
'/cmap/maps/like',
{ id: id },
handleLike,
'json'
);
}
});
$('[id*="commentlike"]').click(function() {
//var map_id = $('#like').find('font').attr('value');
var id = $(this).attr("name");
if (!($(this).hasClass('disabled'))){
$.post(
'/cmap/comments/like',
{ id: id },
handleLike,
'json'
);
}
});
});
</script>
Diagnostic, not solution
Rationalizing and adding an error handler, you should get something like this :
$(document).ready(function() {
function handleLike(v_cb){
alert("Call back chamou!");
$('#erro').html(v_cb.mensagem);
var elemento = (v_cb.class && v_cb.class == 'map') ? $('#maplike') : $('#commentlike'+v_cb.id);
if (!elemento.hasClass('disabled')){
var f = elemento.addClass("disabled").find('font');
f.html(++Number(f.text()));
}
}
function ajaxError(jqXHR, textStatus, errorThrown) {
alert('$.post error: ' + textStatus + ' : ' + errorThrown);
};
$('#maplike').on('click', function() {
var $this = $(this);
if (!$this.hasClass('disabled')) {
$.post('/cmap/maps/like', { id: $this.attr("name") }, handleLike, 'json').fail(ajaxError);
}
});
$('[id*="commentlike"]').on('click', function() {
var $this = $(this);
if (!$this.hasClass('disabled')) {
$.post('/cmap/comments/like', { id: $this.attr("name") }, handleLike, 'json').fail(ajaxError);
}
});
});
untested
Barring mistakes, there's a good chance the error handler will inform you of what's going wrong.
I follow the Kevin B tip and use $ajax method.
It was a parseerror. Sorry.
The return of v_cb was not a json, it was a html. I correct my return, and everything was ok.

jQuery document ready call sequence

I have a following problem with jQuery. I use this code:
function populate_select_from_json(select, json_url) {
select.empty();
$.getJSON(json_url, function(data) {
$.each(data, function(key, value) {
$("<option></option>")
.attr("value", value.name)
.text(value.title)
.appendTo(select);
});
});
select.children(":first").attr("selected", true);
}
$(document).ready(function() {
var value_type = $("#value_type");
populate_select_from_json(value_type, SOME_URL);
var unit = $("#unit");
populate_select_from_json(unit, ANOTHER_URL + value_type.val());
});
I wanted to:
Load the document
Get some JSON data from an associated database
Put the data in #value_type <select> item
Get the value of #value_type select, and query the database once again to populate another select item.
The problem is, when I call value_type.val(), it always outputs null, even though the #value_type <select> is correctly populated. What am I doing wrong here?
I suppose something like this may work better with promises.
Along these lines (untested):
var populate_select_from_json = function($select, json_url) {
$select.empty();
return $.getJSON(json_url, function(data) {
$.each(data, function(key, value) {
$("<option></option>")
.attr("value", value.name)
.text(value.title)
.appendTo($select);
});
$select.children(":first").attr("selected", true);
});
};
$(document).ready(function() {
var $value_type = $("#value_type");
var $unit = $("#unit");
populate_select_from_json($value_type, SOME_URL).done(function(){
populate_select_from_json($unit, ANOTHER_URL + $value_type.val());
});
});

Categories

Resources