Bootstrap button loading + Ajax - javascript

I'm using Twitter Bootstrap's button loading state (http://twitter.github.com/bootstrap/javascript.html#buttons).
HTML:
<input type="submit" class="btn" value="Register" id="accountRegister" data-loading-text="Loading..."/>
JS:
(function ($, undefined) {
$("#accountRegister").click(function () {
$(this).button('loading');
$.ajax({
type:"POST",
url:"/?/register/",
data:$("#loginForm").serialize(),
error:function (xhr, ajaxOptions, thrownError) {
$("#accountRegister").button('reset');
},
success:function (data) {
$("#accountRegister").button('reset');
}
});
return false;
})
})(jQuery);
But if I have many buttons I need to write many functions (?).
Of course I can make something like this:
$(".ajax-button").bind("click", function() {
$(this).button("loading");})
And I can use jQuery Ajax event ajaxComplete
$(".ajax-button").bind("ajaxComplete", function() {
$(this).button("reset");})
But this way ALL buttons will be set to normal state when any Ajax request completed.
If user will click on button1 and then click on button2 (both buttons are sending Ajax request), they will be set to normal state when first Ajax request is completed. How to determine which button I need to set to a normal state?
Thank you in advance.
UPDATE
All I need is determine which button triggered some action (Ajax request), set it state to loading and when Ajax request will be completed set it state to normal.

I found solution for my question =)
After reading jQuery documentation I wrote this code for my system:
core.js:
(function ($, undefined) {
$.ajaxSetup({
beforeSend:function (xhr, settings) {
if (settings.context != undefined && settings.context.hasClass('btn')) {
settings.context.button('loading');
}
},
complete:function () {
this.button('reset');
}
});
})(jQuery);
account.js:
(function ($, undefined) {
$("#accountRegister").click(function () {
$.ajax({
context:$(this), // You need to set context to 'this' element
//some code here
});
return false;
})
})(jQuery);
This works perfectly.
Hope that this will be useful for someone.

Related

How to make JavaScript run after an ajax request updates HTML

My code involves fetching some data using jQuery's Ajax. I then append the result I get from the server to html (in form of buttons). All buttons have a class name mybutton. A separate JavaScript file handles the button click events. Everything works okay for the first Ajax call but I then get an error on second Ajax call. The Ajax calls are made at an interval
HTML code
<button class="mybutton">Button 1</button>
Javascript Code in a SCRIPT1.js file
document.addEventListener("DOMContentLoaded", ready);
function ready() {
let buttons = document.querySelectorAll(".mybutton");
buttons.forEach((button) => {
button.addEventListener("click", () => {
//do some stuff
console.log("I was Clicked");
});
});
}
jQuery CODE in a SCRIPT2.js file
$(document).ready(() => {
//append the html to add more buttons after some time
setInterval(() => {
$.ajax({
method: "GET",
url: "/getButtons",
async: true,
success: function (data, status, xhr) {
data.forEach((item) => {
$("body").append(
'<button class="mybutton">' + item + "</button>"
);
});
const scriptsrc = document.createElement("script");
scriptsrc.setAttribute("type", "text/javascript");
scriptsrc.setAttribute("src", "//script location here");
$("head").append(scriptsrc);
},
});
}, 10000);
});
The JavaScript attached to the buttons only fires up only once after the first Ajax request.The second time I get an error:
Uncaught SyntaxError: Identifier 'buttons' has already been declared
Can you try with the following script? To clarify if the 'let buttons' is issue or the ready() function is overriding the existing one.
document.addEventListener("DOMContentLoaded", init_fun);
function init_fun() {
document.querySelectorAll(".mybutton").forEach((button) => {
button.addEventListener("click", () => {
//do some stuff
console.log("I was Clicked");
});
});
}
Updated due to the comment.
In this case, if you are injecting the script1 after your ajax call, you will have multiple script tags which include multiple variables with the same name.
Instead of adding the whole script, call the function after the success callback of the ajax call. That should avoid multiple variable issues.

Separation of concerns and JQuery AJAX callbacks

I am working on a web application for debtor management and I am refactoring the code and try to adhere to the principle of separation of concerns. But the async nature of AJAX is giving me headaches.
From a jQuery dialog the user can set a flag for a debtor which is then stored in a database. If that succeeds, the dialog shows a notification. Until now I handled everything inside the jQuery Ajax success callback function: validating input, doing the ajax request and updating the content of the dialog.
Of course this lead to spaghetti code.
Thus I created a class AjaxHandler with a static method for setting the flag, which is invoked by the dialog. I thought that the dialog could update itself according the the return value of the AjaxHandler but I did not have the asynchronity in mind.
The following question was helpful in tackling the return values.
How do I return the response from an asynchronous call?
But how can I update the dialog without violating the SoC principle?
EDIT
$("#button").on("click", function() {
var returnValue = AjaxHandler.setFlag();
if(returnValue) { $("#div").html("Flag set"); }
else { $('#div").html("Error setting flag");
});
class AjaxHandler {
static setFlag(){
$.ajax({
type: "POST",
url: "ajax/set_flag.php",
success: function(returndata){
return returndata; //I know this does not work because of
//ASYNC,but that is not the main point.
}
}
})
There is many ways to handle async responses, but the jQuery way is slightly different, so when you are already using jQuery, handle it this way:
$('#button').on('click', AjaxHandler.setFlag)
class AjaxHandler {
static setFlag () {
this.loading = true
this
.asyncReq('ajax/set_flag.php')
.done(function () {
$('#div').html('Flag set')
})
.fail(function (err) {
$('#div').html('Error setting flag. Reason: ' + err)
})
.always(function () {
this.loading = false
})
}
asyncReq (url) {
return $.ajax({
type: 'POST',
url: url
})
}
})
Consider using events perhaps here?
$("#button").on("click", function() {
$('body').trigger('getdata', ["", $('#div')]);
});
$('body').on('getdata', function(event, datasent, myelement) {
var attach = event.delegateTarget;// the body here
var getAjax = $.ajax({
type: "POST",
url: "ajax/set_flag.php",
data: datasent // in case you need to send something
})
.done(function(data) {
$(attach).trigger('gotdata', [data, myelement]);
});
getAjax.fail(function() {});
})
.on('gotdata', function(event, datathing, myelement) {
myelement.html(!!datathing ? "Flag set", "Error setting flag");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
Note that inside those event handlers you could also call some function, pass a namespace for the function, basically do it as you please for your design.

Interplay between <form> and .ajax()

Folks,
I'm learning Ajax by tinkering. At first, I had a form with button, which made an Ajax call to a dummy controller action. The HTML and JavaScript on the client side.1
<form method="post">
<button name="btnSaveProject" title="When you save this project, it willl be available for 30 days.">
Save
</button>
</form>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.1.min.js"></script>
<script>
$(document).ready(function () {
$("button[name='btnSaveProject']").click(function () {
console.log("make ajax call");
$.ajax({
url: "/Project/Save",
type: "GET",
timeout: 8000,
cache: false
}).done(function () {
console.log("ajax call successful");
}).fail(function (jqXHR, textStatus) {
console.log("something went awry. " + textStatus);
}).then(function () {
console.log("always just in case");
});
});
});
</script>
A strange thing was happening when I clicked the button. The Ajax call would reach the server (I know thins because I had a break point in the controller action, which triggered). But neither neither .done(), nor .fail(), nor .always() was getting called back on the client-side.
Then I have moved the <button> out of the <form>, and now .done(), and .always() get called back as expected. There seems to be some interplay between the can Ajax call. What is this interplay? Where can I learn more about it? What do I have to do to be able to use Ajax inside a <form>?
Here's the server-side code, but I suspect that it's a non-factor.
// AJAX: /Project/Save
public ActionResult Save() {
System.Threading.Thread.Sleep(600); /// <bring-up>A bit of latency to make the Ajax call more noticeable.</bring-up>
return Json("lorem ipsum", JsonRequestBehavior.AllowGet);
}
1 I have stripped down the code and kept only the parts that I think are applicable to the question. If I have stripped down too much, please let me know: I'll post more code.
You can add a type to your button:
<button type="button" name="btnSaveProject"
or just prevent the defaults of button to submit the form with event.preventDefault():
$("button[name='btnSaveProject']").click(function (e) {
e.preventDefault();
// other code as is
});
Since the button is in a form its default click action is to submit the form, So in your case as soon as the ajax request is sent the actual page is submitted which I think is reloading the page causing the callback handler to unload that is why those are not getting called
One solution is to prevent the default action of the click event by calling event.preventdefault()
$(document).ready(function () {
$("button[name='btnSaveProject']").click(function (e) {
//prevent the default action of the button click which is to submit the form
e.preventDefault()
console.log("make ajax call");
$.ajax({
url: "/Project/Save",
type: "GET",
timeout: 8000,
cache: false
}).done(function () {
console.log("ajax call successful");
}).fail(function (jqXHR, textStatus) {
console.log("something went awry. " + textStatus);
}).then(function () {
console.log("always just in case");
});
});
});
But since you are using a form, instead of a button click event it will be better to use a form submit event like
$(document).ready(function () {
$("form").submit(function (e) {
//prevent the default action of the button click which is to submit the form
e.preventDefault()
console.log("make ajax call");
//your ajax code
});
});
Another option is to set the type of the button to button so that the form submit will not be triggered like
<button type="button" name="btnSaveProject" title="When you save this project, it willl be available for 30 days.">Save</button>

jQuery onclick event not working upon making multiple ajax requests

I am making few ajax requests in my jQuery file. On success of these jQuery requests, I wrote few on click events which are not working.
This is my code
$(document).ready(function (){
$.ajax ({
type: "POST",
url: 'myServlet',
async: false,
success: function (response) {
id = parseInt(response);
setOutputEvents();
}
});
function setOutputEvents() {
for (var queryNumber = 0; queryNumber <= id; queryNumber++) {
$.ajax({
type: "POST",
url: 'myOtherServlet',
data: {queryNumber: queryNumber},
success: success,
async: false
});
var success = function (response) {
//some code here
generateTable();
}
}
}
function generateTable () {
//some code here
pagination();
}
function pagination(){
$(".class").click(function(event) {
alert();
});
}
$("#me").on("click", function(){
alert("me is triggered");
});
});
I understand making multiple ajax requests is a bad programming practice but what could be the reason for on click events not getting triggered?
These are the onclick events which are not working.
function pagination(){
$(".class").click(function(event) {
alert();
});
}
$("#me").on("click", function(){
alert("me is triggered");
});
I am using Google Chrome Version 39.0.2171.95 on Windows 7.
Please do let me know if any further information is necessary.
Since you use ajax to load even the initial content it seems, .class / #me html elements likely do not exist on initial page load of the DOM. As you didn't post html, i'm guessing this is the case.
Thus, you need to use a delegated event click handler to respond to it
so, you would change
$("#me").on("click", function(){
to
$(document).on("click", "#me", function(){
and so forth to link it to the parent element that does exist, the document itself.
This would work:
$(".class").on("click", function(){
alert("me is triggered");
});
function generateTable () {
//some code here
pagination();
}
function pagination(){
$(".class").trigger("click");
}
Some notes:
Event handler must be registered before triggering click.
Triggered click selector must match the class which has the click event registered.
Functions must be defined before the usage.

Call jquery function when one function completes

So I have a jquery click function assigned to an on/off toggle. Very simple script:
$('.on-off').on('click', function(e) {
e.preventDefault();
var $this = $(this);
$this.find('.slider').toggleClass('active');
});
We have two versions of this toggle. One toggles instantly when clicked and then we submit the value when clicking next(aka submit).
Our other one calls a jquery ajax function that toggles on success and upon success if it is a specific message code that is defined on the backend.
jQuery.ajax({
url: url,
type: 'POST',
dataType: 'json',
cache: false,
data: {'requestType': requestType},
success: function(message) {
if(message.STATUS=='2000'){
if(currentButtonClicked=='dashboardChargingButton'){
if($('#dashboardChargingButton').html()==startCharge)
$('#dashboardChargingButton').html(stopCharge);
else
$('#dashboardChargingButton').html(startCharge);
}
if(currentButtonClicked=='invokeChargingButton'){
$( "#invokeChargingButton .slider" ).toggleClass( 'active');
}
}
},
error: function(xhr, ajaxOptions, thrownError) {
alert(xhr.status + " - " + xhr.statusText);
}
});
}
As you can see I have to toggle the class again using the same code but with direct targeting.
The on off toggles of this type have an onclick inside the actual html calling the function that handles this ajax.
My goal is to have my first set of code the one that targets the element and toggles the class to do all of this, but dynamically to where we don't have to call a function everytime.
Conceptually what I thought is:
$('.on-off').on('click', function(e) {
e.preventDefault();
var $this = $(this);
if (!$this.attr('onclick')) {
$this.find('.slider').toggleClass('active');
} else {
var clickFunction = $this.attr('onclick');
call the clickFunction
if (clickfunction = true) {
$this.find('.slider').toggleClass('active');
}
}
});
What this would do is grab the onclick, but not call it until I specify. And inside the ajax request instead of toggling I would just return true.
This might not be the best method. I am just trying to ecapsulate everything to limit the amount of code as well as make all the dom changes for those elements in one spot for any potential defects.
Here is a link to a basic fiddle of the on/off toggle.
Fiddle
I hope I explained everything in good enough detail.

Categories