I have a huge problem with working with AJAX:
After the AJAX request on my page is send the next request are send multiple times, and buttons think that they are pressed multiple times.
Now I searched around here and the internet, but I can't solve it. So far, following corrections are made in the code:
All code is in an own function called AjaxInit()
AjaxInit() is called upon $(window).load and on $(document).ajaxStop
All Element have their binder to body (e.g. $("body").on("click","#btn-main", function)
Now I have tried unbinding all events using $("body").find("*").off(), but that did not help either.
I know that I do something wrong, I just don't know what.
How can I properly rebind everythink after the Ajax call is done? How can I make shure that object bindings (e.g. $("#news").sortable({})) will work properly after the first ajax call? I would love to use AJAX for all the callbacks on my page, but currently the best solution seems to be just reloading the entire page after every ajax call, which would be rather bad.
Any help is appreciated.
EDIT: Code added
$(window).load(function() {
AjaxInit();
});
$(document).ajaxStop(function() {
AjaxInit();
});
function AjaxInit() {
$("body").on("click", "#btn-admin-main", function(e) {
console.log("Admin clicked");
e.handled = true;
e.preventDefault();
LoadDynamicContent("/Edit/");
});
}
function LoadDynamicContent(path) {
//Nach oben Scrollen
$('html,body').scrollTop(0);
$.ajax({
type: 'GET',
url: path,
success: function(response) {
var html_response = $(response).find('#dynamic_content').html();
$("#dynamic_content").html(html_response);
}
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<a class="sidebutton-full" id="btn-main">Edit</a>
<div id="dynamic_content"></div>
You can unbind the click event from button
$(document).unbind('click').on("click", "#btn-main", function () {
//do stuff here
});
OR
$(document).off("click", "#btn-news").on("click", "#btn-news", function () {
});
If your form submission hitting twice then you need to change your code little bit
$("#form_news_sort").submit(function(e){
e.preventDefault()
// do stuffer here
.
.
.
.
return false;
})
if you are still facing error , please comment below
The problem is that when your ajaxStop handler calls AjaxInit(), it adds another click handler to the body.
In your example code, it looks like you don't need ajaxStop at all. All it will do is add another click handler, which is the problem. Or if your real code does some more complex initialization that needs to run whenever all Ajax requests are complete, you should factor out the click handler assignment from whatever else needs to happen.
Related
I am working on an OnsenUI powered app.
It is having multiple pages.
I am using postpush event to fire my ajax requests for data.
Like below.
$scope.navi.on('postpush', function () {
//ajax code here
});
Now the issue is, my complete code looks like below.
$scope.navi.pushPage('linkone.html');
$scope.navi.on('postpush', function () {
//ajax 1
});
$scope.navi.pushPage('linktwo.html');
$scope.navi.on('postpush', function () {
//ajax 2
});
If I navigate to linkone.html page it fires the ajax1.
After that if I navigate to linktwo.html it fires ajax1 and ajax2 both.
I want only relevant ajax to be fired. But both the events are getting fired. And if I keep on browsing pages, eventually too many requests starts getting fired.
Can anyone help me regarding this?
What you are explaining is actually the expected behaviour. The on method adds a listener to be executed whenever the event becomes triggered. You seem to be adding more listeners without removing them.
Alternatives:
A simple alternative would be the once method which will be executed only once and then it will remove the listener automatically.
Instead of adding listeners you can just queue the ajax as a callback to the pushPage - either of these:
$scope.navi.pushPage('linkone.html', {callback: ajax1});
$scope.navi.pushPage('linkone.html').then(ajax1);
should be fine.
You can add one listener which does different things depending on your page:
$scope.navi.pushPage('linkone.html');
$scope.navi.on('postpush', function(ev){
if (ev.enterPage.id === 'page1') {
ajax1();
} else if (ev.enterPage.id === 'page2') {
ajax2();
}
});
The same thing can probably also be achieved with the page's init event.
document.addEventListener('init', function(ev) {
if (ev.target.id === 'page1') {
ajax1();
} else if (ev.target.id === 'page2') {
ajax2();
}
});
However do note that in this third alternative page1 and page2 must be the ids of the ons-page elements, not the templates'.
I am making and ajax call and storing the results in an array. After the first set of data is loaded, I am using next and previous buttons to navigate through the array.
I want to prevent any $(element).on('click') events from happening until I have the first set of data loaded.
Is there any way to do this?
I have already tried to use
$(element).unbind('click');
for when the document loads and then
$(element).bind('click');
when the ajax call is successful, but still clicking on either the next or previous links will still trigger my
$('#next #prev').on('click', function () {
//my code to navigate through the array here.
});
Anyone have any ideas on how I can complete stop this event from firing until the ajax has loaded?
You can disable them by default and in the ajax success callback you can turn them on with something like this:
$(element).prop("disabled", false); // Element will get enabled for clicking
I will update the answer now as it is not working for the concerned person, to disable the button do this:
$(element).attr(“disabled”, true);
In success callback of the ajax call you need to do this:
$(element).removeAttr('disabled');
$.ajax({
....
success:function(){
$('#next #prev').on('click', function(){
// only ajax event complete the #prev can run this function
}).off('click'); // no more clickable now
}
});
or you can just
$('#next #prev').hide();
// done?
$('#next #prev').show();
Is there an event handler to use in JQuery when a DOM select element has finished loading?
This is what I want to achieve. It is working with other events except 'load'.
This piece of code is loaded in the head.
$(document).on('load', 'select', function(){
var currentSelectVal = $(this).val();
alert(currentSelectVal);
} );
The question was badly formed earlier. I need to attach the event handler to all select elements, both present when the document is loaded and dynamically created later.
They are loaded from a JQuery Post to a php-page. Similar to this:
$.post("./user_functions.php",
{reason: "get_users", userID: uID})
.done(function(data) { $("#userSelector").html(data);
});
I think we're all confused. But a quick break down of your options.
After an update made to the Question, it looks like the answer you might seek is my last example. Please consider all other information as well though, as it might help you determine a better process for your "End Goal".
First, You have the DOM Load event as pointed out in another answer. This will trigger when the page is finished loading and should always be your first call in HEAD JavaScript. to learn more, please see this API Documentation.
Example
$(document).ready(function () {
alert($('select').val());
})
/* |OR| */
$(function() {
alert($('select').val());
})
Then you have Events you can attach to the Select Element, such as "change", "keyup", "keydown", etc... The usual event bindings are on "change" and "keyup" as these 2 are the most common end events taking action in which the user expects "change". To learn more please read about jQuery's .delegate() (out-dated ver 1.6 and below only), .on(), .change(), and .keyup().
Example
$(document).on('change keyup', 'select', function(e) {
var currentSelectVal = $(this).val();
alert(currentSelectVal);
})
Now delegating the change event to the document is not "necessary", however, it can really save headache down the road. Delegating allow future Elements (stuff not loaded on DOM Load event), that meet the Selector qualifications (exp. 'select', '#elementID', or '.element-class') to automatically have these event methods assigned to them.
However, if you know this is not going to be an issue, then you can use event names as jQuery Element Object Methods with a little shorter code.
Example
$('select').change(function(e) {
var currentSelectVal = $(this).val();
alert(currentSelectVal);
})
On a final note, there is also the "success" and "complete" events that take place during some Ajax call. All jQuery Ajax methods have these 2 events in one way or another. These events allow you to perform action after the Ajax call is complete.
For example, if you wanted to get the value of a select box AFTER and Ajax call was made.
Example
$.ajax({
url: 'http://www.mysite.com/ajax.php',
succuess: function(data) {
alert($("select#MyID").val());
}
})
/* |OR| */
$.post("example.php", function() { alert("success"); })
.done(function() { alert($("select#MyID").val()); })
/* |OR| */
$("#element").load("example.php", function(response, status, xhr) {
alert($("select#MyID").val());
});
More reading:
.ajax()
.get()
.load()
.post()
Something else to keep in mind, all jQuery Ajax methods (like .get, .post) are just shorthand versions of $.ajax({ /* options|callbacks */ })!
Why dont you just use:
$(document).ready(function () {
//Loaded...
});
Or am I missing something?
For your dynamic selects you can put the alert in the callback.
In your .post() callback function, try this:
.done(function(data) {
data = $(data);
alert(data.find("select").val());
});
Ok, correct me if I understand this wrong. So you want to do something with the selects when the document is loaded and also after you get some fresh data via an ajax call. Here is how you could accomplish this.
First do it when the document loads, so,
<script>
//This is the function that does what you want to do with the select lists
function alterSelects(){
//Your code here
}
$(function(){
$("select").each(function(){
alterSelects();
});
});
</script>
Now everytime you have an ajax request the ajaxSend and ajaxComplete functions are called. So, add this after the above:
$(document).ajaxSend(function () {
}).ajaxComplete(function () {
alterSelects();
});
The above code will fire as soon as the request is complete. But I think you probably want to do it after you do something with the results you get back from the ajax call. You'll have to do it in your $.post like this:
$.post("yourLink", "parameters to send", function(result){
// Do your stuff here
alterSelects();
});
Do you want all Selects to be checked when the User-Select is loaded, or just the User-Select?...
$.post("./user_functions.php", {reason: "get_users", userID: uID}).done(function(data) {
$("#userSelector").html(data);
//Then this:
var currentSelectVal = $("#userSelector").val();
alert(currentSelectVal);
});
If your select elements are dynamically loaded, why not add the event handler after you process the response?
e.g. for ajax
$.ajax({
...
success: function(response) {
//do stuff
//add the select elements from response to the DOM
//addMyEventHandlerForNewSelect();
//or
//select the new select elements from response
//add event handling on selected new elements
},
...
});
My solution is a little similar to the posters above but to use the observer (pubsub) pattern. You can google for various pub sub libraries out there or you could use jQuery's custom events. The idea is to subscribe to a topic / custom event and run the function that attach the event. Of course, it will be best to filter out those elements that have been initialize before. I havent test the following codes but hopefully you get the idea.
function attachEventsToSelect(html) {
if (!html) { // html is undefined, we loop through the entire DOM we have currently
$('select').doSomething();
} else {
$(html).find('select').doSomething(); // Only apply to the newly added HTML DOM
}
}
$(window).on('HTML.Inserted', attachEventsToSelect);
// On your ajax call
$.ajax({
success: function(htmlResponse) {
$(window).trigger('HTML.Inserted', htmlResponse);
}
});
// On your DOM ready event
$(function() {
$(window).trigger('HTML.Inserted'); // For the current set of HTML
});
I am using AJAX to submit a form behind the scenes, without refreshing the page. The problem I am running into is I can only submit the form once. After I submit it once, the on('submit') function no longer works and I am getting no errors. This completely defeats the purpose of using AJAX to submit the form :/
$(document).on('submit', '#myForm', function(e) {
$.post('mail.php', $(this).serialize(), function (data) {
//SUCCESS
$('.successORfail').html(data);
setTimeout(function(){
$(".successORfail").fadeOut("slow", function () {
$(".successORfail").remove();
});
}, 4500);
}).error(function() {
alert("Fatal Error: mail.php not found!");
});
e.preventDefault();
});
I was wondering if someone ran into a similar problem or knows how to solve this? I would like to be able to submit the form more than once, making changes to the form input values after each submit, if needed.
Many thanks in advance
Are you sure the AJAX request is not happening? It looks like you are removing the .successORfail element from the page, and thus the there is nothing to append the content to on subsequent calls.
Check your console and you will probably notice an ajax call happening each time.
Try changing your setTimeout to this:
var msgEl = $(".successORfail");
setTimeout(function() {
msgEl.fadeOut("slow", function () {
msgEl.empty().show();
});
}, 4500);
Your success event handler:
$('.successORfail').html(data);
setTimeout(function () {
$(".successORfail").fadeOut("slow", function () {
$(".successORfail").remove();
});
}, 4500);
is setting content in an element (.successORfail), then removing that element. The next time you submit the form, get a successful response, and that function is executed the element is no longer there to set the content into so you wouldn't see anything change.
Instead of removing the element, just .hide() it so that the next time it can be populated. You'll need to .show() it each time too.
$(document).on('submit', '#myForm', function(e) {
$.post('mail.php', $(this).serialize(), function (data) {
//SUCCESS
$('.successORfail').html(data).show(); //<-- show
setTimeout(function(){
$(".successORfail").fadeOut("slow", function () {
$(this).hide(); //<-- hide
});
}, 4500);
}).error(function() {
alert("Fatal Error: mail.php not found!");
});
e.preventDefault();
});
Also in the fadeOut() function, you can access the element with $(this) instead of re-selecting it based on the class name.
Can you add some HTML-snippet? Its hard to help without knowledge about your html-structure, because if you are replacing the form via $('.successORfail').html(data); the listener isn't re-bound to the form.
You should also return FALSE because the form-data is sent via javascript.
Well, it seems that you append your result to $('.successORfail').html(data); and the remove it. Take out the following and it should work multiple times...
$('.successORfail').remove();
Without that element, the change can't be made.
I currently have several action buttons in different pages, and each button performs some AJAX call when clicked. In another word, I have code like this all over the places:-
$("#searchButton")
.button()
.click(function() {
...
$.get(url, { data: ...}, function(data) { ... });
...
});
After doing some testing, it seems like some AJAX calls take at least more than a few seconds to process before the callback function is being called.
My plan is to disable the button when the AJAX call is made and enable it back when the AJAX call is completed. This is to prevent user from clicking the button too many times when the request is being processed. One solution I found is to utilize the unbind() and bind() functions. After modifying my code, it looks like this now:-
var searchButtonClickHandler = function() {
...
$.get(url, { data: ...}, function(data) { ... });
...
};
$("#searchButton")
.button()
.ajaxStart(function() {
$(this).button("disable").unbind("click");
})
.ajaxStop(function() {
$(this).button("enable").bind("click", searchButtonClickHandler);
})
.click(searchButtonClickHandler);
This code works fine. Basically, it removes the click handler when the AJAX call is made and addes the click handler back when the AJAX call is completed.
My question is... is it possible to generalize the button disabling/enabling so that I don't have to implement ajaxStart() and ajaxStop on all UI buttons?
Ideally, I would like to use my earlier code snippet to register only the click event handler on the button, and then enable/disable all buttons using the .ui-button selector, something like this...
$(".ui-button")
.ajaxStart(function() {
$(this).button("disable").unbind("click");
})
.ajaxStop(function() {
// not sure how to bind the handler here
$(this).button("enable").bind("click", ?? );
});
... but, this doesn't work and I run into trouble in binding the click handler here.
The more I think about it, it almost seems like I need to create a button builder function to do this, for example:-
var createButton = function(selectorName, clickHandler) {
$(selectorName)
.button()
.ajaxStart(function() {
$(this).button("disable").unbind("click");
})
.ajaxStop(function() {
$(this).button("enable").bind("click", clickHandler);
})
.click(clickHandler);
};
// create button like this
createButton("#searchButton", function() {
...
$.get(url, { data: ...}, function(data) { ... });
...
});
... but this approach will only disable/enable the selected button, and I want to apply that to all UI buttons.
Do anyone has a better approach in disabling/enabling all the buttons in the page?
Thanks.
Different approach, according to this answer you should be able to get a reference to your previous event handler via .data("events");
Putting that together with your sample it should look like this:
$(".ui-button")
.ajaxStart(function() {
var events = $(this).data("events");
$(this).data("oldEvent", events.click[0]);
$(this).button("disable").unbind("click", events.click[0]);
})
.ajaxStop(function() {
var oldClick = $(this).data("oldEvent");
$(this).button("enable").bind("click", oldClick.handler);
});
Not sure if this will work completely yet, still messing around on jsfiddle.
Update
This should work, example on jsfiddle.
you can use $('input[type=button]').attr('disabled','disable'); to disable all buttons instead of binding and unbinding click event to the buttons... also you can use deferred jquery object, here is an example
Maybe you could attach your handler to the parent element of your buttons with delegate? That way there's only one handler function to bind/unbind.
Yahoo hosts a getElementByClass function, and you could assign a class such as "disableMe" to all your UI buttons. Then use getElementByClass('disableMe') to return an array of all the elements you want to disable.
The link: http://developer.yahoo.com/yui/dom/
You can use
$("button").each(function(){
//your code here
});