I'm using AJAX to submit the form without reloading. I'm using it for my register form. After I catch my error/success message I append it to my div and remove it after 5 seconds using timeout function.
Now if the user clicks on the button and gets error, and then again clicks the button (before 5 seconds pass) the second error message div will appear with the same error but it will be removed at the same time the first one is removed. So what I'm trying to achieve is to set my error/success messages to have individual timeouts. So first error appears, then after 2 seconds I press the button again and get second error, now the first error will be removed after 5 seconds, and the second will stay untill its 5 seconds pass.
So I have a div in my HTML code with the id "msg-response", where my error/success messages appear.
And here is how I call them:
$("#registerform").submit(function(event) {
var ajaxRequest;
event.preventDefault();
$("#result").html('');
var values = $(this).serialize();
ajaxRequest = $.ajax({
url: "include/auth/register.php",
type: "post",
data: values
});
ajaxRequest.done(function (response){
if ($.trim(response) == 'error') {
$("#msg-response").prepend("<div class='error-msg'>Email format isn't valid. Try again.</div>").hide().fadeIn("slow");
setTimeout(function() {
$('.error-msg').fadeOutAndRemove('slow');
}, 5000);
}
});
ajaxRequest.fail(function (){
alert("error");
});
});
So how can I add individual timeouts to each div appeared? And not one timeout for all divs with class .error-msg.
Thanks in advance.
You can store your .error-msg inside a var and then remove it by var reference:
var error = $("<div class='error-msg'>Email format isn't valid. Try again.</div>");
error.fadeOutAndRemove('slow');
Final code:
if ($.trim(response) == 'error') {
var error = $("<div class='error-msg'>Email format isn't valid. Try again.</div>");
$("#msg-response").prepend(error).hide().fadeIn("slow");
setTimeout(function() {
error.fadeOutAndRemove('slow');
}, 5000);
}
Intresting, I got it working by making my error-msg div to be an ID instead of CLASS, so like this:
$("#registerform").submit(function(event) {
var ajaxRequest;
event.preventDefault();
$("#result").html('');
var values = $(this).serialize();
ajaxRequest = $.ajax({
url: "include/auth/register.php",
type: "post",
data: values
});
ajaxRequest.done(function (response){
if ($.trim(response) == 'error') {
$("#msg-response").prepend("<div id='error-msg'>Email format isn't valid. Try again.</div>").hide().fadeIn("slow"); // Changed line
setTimeout(function() {
$('#error-msg').fadeOutAndRemove('slow'); // Changed line
}, 5000);
}
});
ajaxRequest.fail(function (){
alert("error");
});
});
I'm confused a little, so can atleast someone write me explanation why its good now that I'm using ID and not while using classes? And is this the right approach?
Related
This question already has an answer here:
Jquery button click event not firing
(1 answer)
Closed 8 years ago.
I have an auto refreshing HTML table with some buttons in it.
I current use the folowing Code to Refresh the Table every 5 seconds and set the ajax ClickListener. My problem is that the event ONLY fire before the first refresh fired.
<?php require_once ('UserTableHtml.php'); ?>
<script type='text/javascript'>
var table = $("#t02");
// refresh every 5 seconds
var refresher = setInterval(function()
{
table.load("UserTableHtml.php");
}, 5000);
table.ready(function()
{
$('.btnUser').click(function()
{
var clickBtnValue = $(this).val();
var ajaxurl = 'home.php',
data = {'action': clickBtnValue};
$.post(ajaxurl, data, function (response)
{
// Response goes here.
alert("action performed successfully");
});
});
});
</script>
The complete code of the output table is generated by the 'UserTableHtml.php'
Thanks for your answers an MERRY CHRISTMAS
If the problem is with the click of the button, you should use
$('.btnUser').on('click',function(){...});
Insted of
$('.btnUser').click(function(){...});
For dynamic elements, attach events using the .on() annotation.
Looks like it only loads after 5 seconds... add the line below to have it load after the table has finished rendering.
<script type='text/javascript'>
var table = $("#t02");
// refresh every 5 seconds
var refresher = setInterval(function()
{
table.load("UserTableHtml.php");
}, 5000);
table.ready(function()
{
$('.btnUser').click(function()
{
var clickBtnValue = $(this).val();
var ajaxurl = 'home.php',
data = {'action': clickBtnValue};
$.post(ajaxurl, data, function (response)
{
// Response goes here.
alert("action performed successfully");
});
});
//add this here...
table.load("UserTableHtml.php");
});
</script>
Guys i just figured it out.
Now it works as excepted.
var table = $("#t02");
table.ready(function()
{
$(document).on('click', '.btnUser',function()
{
var clickBtnValue = $(this).val();
var ajaxurl = 'home.php',
data = {'action': clickBtnValue};
$.post(ajaxurl, data, function (response)
{
// Response div goes here.
alert("action performed successfully");
});
});
});
<button type="submit" class="btnUser" name="userEdit" value="user_edit_'.$user->getId().'"><img src="images/edit-4.png" />
This topic is covered in a few other questions, but I had some difficulty applying the suggested approaches into this use case. I have a checkbox list, where a user can select n sub-sites to publish their post to. since this list could grow to be 100+, I need an efficient way to perform an expensive task on each one. It's okay if it takes awhile, as long as Im providing visual feedback, so I planned to apply an "in progress" style to each checkbox item as its working, then move to the next item int he list once it is successfully published. Also note: I'm working in the WordPress wp_ajax_ hook but the PHP side of things is working well, this is focused on the JS solution.
This code is working right now (console.logs left in for debug), but I've seen multiple warnings against using async: true. How can I achieve a waterfall AJAX loop in a more efficient way?
//Starts when user clicks a button
$("a#as_network_syndicate").click( function(e) {
e.preventDefault(); //stop the button from loading the page
//Get the checklist values that are checked (option value = site_id)
$('.as-network-list').first().find('input[type="checkbox"]').each(function(){
if($(this).is(':checked')){
blog_id = $(this).val();
console.log(blog_id+' started');
$(this).parent().addClass('synd-in-progress'); //add visual feedback of 'in-progress'
var process = as_process_syndication_to_blog(blog_id);
console.log('finished'+blog_id);
$(this).parent().removeClass('synd-in-progress');
}
});
});
function as_process_syndication_to_blog(blog_id){
var data = {
"post_id": $('#as-syndicate_data-attr').attr("data-post_id"), //these values are stored in hidden html elements
"nonce": $('#as-syndicate_data-attr').attr("data-nonce"),
"blog_id": blog_id
};
var result = as_syndicate_to_blog(data);
console.log('end 2nd func');
return true;
}
function as_syndicate_to_blog(data){
$.ajax({
type : "post",
dataType : "json",
async: false,
url : ASpub.ajaxurl, //reference localized script to trigger wp_ajax PHP function
data : {action: "as_syndicate_post", post_id : data.post_id, nonce: data.nonce, blog_id: data.blog_id},
success: function(response) {
if(response.type == "success") {
console.log(response);
return response;
} else {
}
},
error: {
}
});
}
Indeed, doing synchronous AJAX request is bad because it will block the browser during the whole AJAX call. This means that the user cannot interact with your page during this time. In your case, if you're doing like 30 AJAX calls which take say 0.5 seconds, the browser will be blocked during 15 whole seconds, that's a lot.
In any case, you could do something following this pattern:
// some huge list
var allOptions = [];
function doIntensiveWork (option, callback) {
// do what ever you want
// then call 'callback' when work is done
callback();
}
function processNextOption () {
if (allOptions.length === 0)
{
// list is empty, so you're done
return;
}
// get the next item
var option = allOptions.shift();
// process this item, and call "processNextOption" when done
doIntensiveWork(option, processNextOption);
// if "doIntensiveWork" is asynchronous (using AJAX for example)
// the code above might be OK.
// but if "doIntensiveWork" is synchronous,
// you should let the browser breath a bit, like this:
doIntensiveWork(option, function () {
setTimeout(processNextOption, 0);
});
}
processNextOption();
Notice: as said by Karl-André Gagnon, you should avoid doing many AJAX requests using this technique. Try combining them if you can, it will be better and faster.
If you can't pass the whole block to the server to be processed in bulk, you could use a jQuery queue. This is using your sample code as a base:
var $container = $('.as-network-list').first();
$container.find('input[type="checkbox"]:checked').each(function(){
var $input = $(this);
$container.queue('publish', function(next) {
var blog_id = $input.val(),
$parent = $input.parent();
console.log(blog_id+' started');
$parent.addClass('synd-in-progress'); //add visual feedback of 'in-progress'
as_process_syndication_to_blog(blog_id).done(function(response) {
console.log(response);
console.log('finished'+blog_id);
$parent.removeClass('synd-in-progress');
next();
});
});
});
$container.dequeue('publish');
function as_process_syndication_to_blog(blog_id){
var data = {
"post_id": $('#as-syndicate_data-attr').attr("data-post_id"), //these values are stored in hidden html elements
"nonce": $('#as-syndicate_data-attr').attr("data-nonce"),
"blog_id": blog_id
};
return as_syndicate_to_blog(data).done(function(){ console.log('end 2nd func'); });
}
function as_syndicate_to_blog(data){
return $.ajax({
type : "post",
dataType : "json",
url : ASpub.ajaxurl, //reference localized script to trigger wp_ajax PHP function
data : {action: "as_syndicate_post", post_id : data.post_id, nonce: data.nonce, blog_id: data.blog_id}
});
}
I don't have a test environment for this so you may need to tweak it for your use case.
I have got a form with two tabs, on both tabs you can edit data and submit your changes which is working already.
Now I want the tab where you made changes to get reloaded after you changed something (e.g. a picture URL and the thumbnail should get refreshed) to see the changes.
I have this code for the second tab
<script>
$(document).ready(function(){
$('.btn').click(function(){
var clickBtnValue = $(this).val();
if(clickBtnValue == 'Save') {
var ajaxurl = 'ajax.php',
data = $('form').serialize();
$.post(ajaxurl, data, function (response) {
if(response == '')
{
alert("Successfully saved");
location.href="catalog.php";
}
else alert(response);
});
}
else if(clickBtnValue == 'Save & Continue Edit')
{
var ajaxurl = 'ajax.php',
data = $('form').serialize();
$.post(ajaxurl, data, function (response) {
if(response == '') alert("Successfully saved");
else alert(response);
});
}
else if(clickBtnValue == 'Add new Item')
{
var ajaxurl = 'ajax.php',
data = $('#itemform').serialize();
$.post(ajaxurl, data, function (response) {
if(response == '')
{
alert("Successfully added new Item");
location.href="catalog.php";
}
else alert(response);
});
}
else if(clickBtnValue == 'Save Images')
{
var ajaxurl = 'saveimages.php',
data = $('#imageform').serialize();
$.post(ajaxurl, data, function (response) {
if(response == '')
{
alert("Successfully saved");
$("#tab_images").load(location.href+" #tab_images>*","");
}
else alert(response);
});
}
});
});
Everything is working until now, the data get saved and the DIV reloads, but now whenever I try to press a button nothing happens, even on the first tab.
What am I doing wrong?
EDIT:
My Tab Code: http://i.epvpimg.com/9SaKb.png
Can't post it here since it is too long so I had to make a screenshot.
It looks like the buttons you try to click are inside the div what you are reloading. When the content of that div is replaces, all the elements you fetched with ajax are considered as new - that also means that the click handlers you had previously on those buttons are also lost - hence they don't react the same way :D
try binding the event not on the button itself but an element outside the div that is being replaced
$("parent_selector_outside_ajax_div").on("click", ".btn", function() {
//your button function
});
read move about event delegation with jQuery at http://api.jquery.com/on/
As your external js library binds it's own buttons I suggest moving those buttons outside the div you are trying to update (which shouln't be a big problem as you are trying to update only for the sake of them image previews? :D).
The other alternative (which I wouln't do) would be to rebind those buttons again after the ajax has reloaded by calling whatever function the library offers to initialize itself. If your application is long lived, you also should, before replacing the old content with a new one, remove all the event handlers from the current content, to avoid possible memory leaks in some browsers (not sure what is your target audience).
I am using Magnific Popup version 0.8.9.
I am loading content into it via Ajax, and I use a callback for ajaxContentAdded. This callback sets up an event handler for submitting a form that was loaded into the popup, like so:
$('.add-item-btn').magnificPopup({
type: 'ajax',
closeOnContentClick: false,
callbacks: {
ajaxContentAdded: HandleItemFormSubmit
}
});
This works fine, the form submit is handled correctly. The event handler function posts it to the server, which (in case of errors) returns the entire form including error messages.
For this purpose I let it replace the popup's content with the returned form, and setup the submit handler again.
function HandleItemFormSubmit()
{
var popup = this;
// Submit form using ajax
$('form.item-form').submit(function()
{
var data = $(this).serialize();
var url = $(this).attr('action');
$.post(url, data, function(resp)
{
if (resp == 'OK')
{
// All good, close up
popup.close();
}
else
{
// Show HTML from response (with errors)
popup.closeOnContentClick = false;
popup.content.replaceWith(resp);
popup.updateItemHTML();
HandleItemFormSubmit();
}
});
return false;
});
}
However, despite setting closeOnContentClick to false at two different points, the popup immediately closes when content is clicked after the content was replaced (it does work the first time).
The content in the popup has a single root element by the way.
I hope the author or someone else can help out here, I have no idea what is wrong here.
Thank you very much!
I've found another solution:
$('html').on('submit', '#UR_FORM', function(e) {
e.preventDefault();
$.ajax({
data: $(this).serialize(),
type: $(this).attr('method'),
url: $(this).attr('action'),
success: function(response) {
var magnificPopup = $.magnificPopup.instance;
magnificPopup.items[0].type = "inline";
magnificPopup.items[0].src = response;
magnificPopup.updateItemHTML();
}
});
});
You need to call the HandleItemFormSubmit for the popup object:
HandleItemFormSubmit.call(popup);
Otherwise when you call it the way you do, HandleItemFormSubmit();, the this will be set to window and this will not work as expected.
Update
Use this in the else clause:
if (resp == 'OK')
{
popup.close();
}
else
{
// Show HTML from response (with errors)
popup.closeOnContentClick = false;
popup.content.replaceWith(resp);
popup.updateItemHTML();
HandleItemFormSubmit.call(popup);
}
I have an AJAX function to check for new messages and then prepend the new messages to the #message. But, my problem is that this function triggers every 20 seconds, but whenever you click the Refresh button that instantly triggers the function, it messes up. Here is my functions for the AJAX:
function ajaxMail() {
var message_id = $('.line:first').attr('id');
jQuery.ajax({ //new mail
type: 'get',
dataType: 'text',
url: "/employee/message/check_mail.php",
data: {
latest_id: message_id,
t: Math.random()
},
success: function(data, textStatus) {
$('#messages_inner').prepend(data);
}
});
}
function updateTitles() {
//if(titleChange !== false) {
$.get('update.php?type=title', function(data) {
document.title = data;
});
//}
$.get('update.php?type=header', function(data) {
$('#heading').html(data);
});
$.get('update.php?type=total', function(data) {
$('#total').html('Total messages: ' + data);
});
setTimeout("updateTitles();ajaxMail();", 20000);
}
updateTitles();
And for the Refresh button this is what I use:
$(document).ready(function() {
$('#refresh').click(function() {
ajaxMail();
updateTitles();
});
});
Sometimes, the same exact message gets prepended to the message div because of the button or something. (but when I refresh of course there aren't 2 of the same message anymore) This is one time when the same message was prepended multiple times:
First, I pressed the Refresh button and it prepended the new message. But then about 5 seconds later the funciton triggered again and for some reason prepended the same message again. Also as you can see the Inbox count says 2 because really there is only 2 ("Test" and "Test12345"), but for some reason the "Test12345" got prepended 2 times.
Does anyone know why it is doing this? I can also provide the code for check_mail.php if you need to see it.
I'd recommend trying cache:false too, I've had browsers caching an ajax request even through I was sending a random string along.
Also, consider clearing the timeout before you set it again, as each time the refresh button is pressed it starts another timeout.