I am implementing a twitter-style follow/unfollow functionality with the following jquery.
$(function() {
$(".follow").click(function(){
var element = $(this);
var I = element.attr("id");
var info = 'id=' + I;
$("#loading").html('<img src="loader.gif" >');
$.ajax({
type: "POST",
url: "follow.php",
data: info,
success: function(){
$("#loading").ajaxComplete(function(){}).slideUp();
$('#follow'+I).fadeOut(200).hide();
$('#remove'+I).fadeIn(200).show();
}
});
return false;
});
});
I have a similar unfollow function. However i have the following problem:
When I have N items {1,2..i.N} each with id = followi and I click on the follow button. I find that some of the items respond while others do not. I suspect it is a pure javascript issue...otherwise i figure none of the buttons would respond at all.
Is it a timing issue...all help is appreciated. Also i'd appreciate it if you could point me to a simpler method.
Thanks!
Well you are doing the UI update in your ajax success handler, so the reaction time for the UI updated is based on the speed of the Ajax response. And if the server doesn't return successfully, the UI update won't happen at all.
A simpler method with instant response:
$(function() {
$(document.body).delegate(".follow","click",function(){
var element = $(this);
var I = element.attr("id");
var info = 'id=' + I;
$("#loading").html('<img src="loader.gif"/>');
$('#follow'+I).fadeOut(200); // act instantly since we assume it will go well
$('#remove'+I).fadeIn(200); // act instantly since we assume it will go well
$.ajax({
type: "POST",
url: "follow.php",
data: info,
complete: function(){ //always remove the loader no matter if it goes well or not
$("#loading").slideUp();
},
error: function() {
//handle error
$('#follow'+I).fadeIn(200); // correct mistake
$('#remove'+I).fadeOut(200); // correct mistake
}
});
return false;
});
});
Related
I Am working on my project i have added feature for image search and i am having little trouble i have bounded min 2 characters when ajax fire but when i type more then 2 chars ajax run after every letter i don't want that to happen instead i want to run ajax only after when user finishes typing i found few questions related to this i have tried as much as i can but they did not helped me.
Update:-
And one more thing when user clears input box my loader is still there i want to hide loader if input is empty
My Jquery:-
$(function() {
var minlength = 2;
$("#image_query").keyup(function() {
$('#span_result').html('<div class="loader">Loading...</div>');
var that = this,
value = $(this).val();
if (value.length >= minlength) {
$.ajax({
type: "GET",
url: "image.php",
data: {
'image_query': value
},
dataType: "text",
success: function(html) {
if (value == $(that).val()) {
$("#span_result").html(html)
}
}
})
}
})
});
My HTML:-
<form method="get" action="">
<input type="text" id="image_query" placeholder="Search Here For Images">
<button type="submit">Go</button>
Although there are probably more optimal ways - I always find this the easiest and best ways. I think this is what you are looking for. Also please note the hide image should go in the ajax success callback.
var timeout = null;
var minlength = 2;
$("#image_query").keyup(function() {
$('#span_result').html('<div class="loader">Loading...</div>');
// clear last timeout check
clearTimeout(timeout);
var that = this;
var value = $(this).val();
if (value.length >= minlength) {
//
// run ajax call 1 second after user has stopped typing
//
timeout = setTimeout(function() {
$.ajax({
type: "GET",
url: "image.php",
data: {
'image_query': value
},
dataType: "text",
success: function(html) {
// hide image
$(#span_result .loader).hide();
if (value == $(that).val()) {
$("#span_result").html(html)
}
}
});
}, 1000);
});
});
I think, then you should use setTimeout() along with keyup event before sending the ajax request. The delay could be 2 or 3 seconds, as per your need.
Edit:
To clear the loader image, you can do following:
$(#span_result .loader).hide();
At the end inside AJAX response.
You could use the jQuery blur() method to capture when the user is finished with input. Then check for minlength inside the blur function before your ajax call.
You can find an example of blur in W3 schools here
I have a PHP populated table from Mysql and I am using JQuery to listen if a button is clicked and if clicked it will grab notes on the associated name that they clicked. It all works wonderful, there is just one problem. Sometimes when you click it and the dialog(JQuery UI) window opens, there in the text area there is nothing. If you are to click it again it will pop back up. So it seems sometimes, maybe the value is getting thrown out? I am not to sure and could use a hand.
Code:
$(document).ready(function () {
$(".NotesAccessor").click(function () {
notes_name = $(this).parent().parent().find(".user_table");
run();
});
});
function run(){
var url = '/pcg/popups/grabnotes.php';
showUrlInDialog(url);
sendUserfNotes();
}
function showUrlInDialog(url)
{
var tag = $("#dialog-container");
$.ajax({
url: url,
success: function(data) {
tag.html(data).dialog
({
width: '100%',
modal: true
}).dialog('open');
}
});
}
function sendUserfNotes()
{
$.ajax({
type: "POST",
dataType: "json",
url: '/pcg/popups/getNotes.php',
data:
{
'nameNotes': notes_name.text()
},
success: function(response) {
$('#notes_msg').text(response.the_notes)
}
});
}
function getNewnotes(){
new_notes = $('#notes_msg').val();
update(new_notes);
}
// if user updates notes
function update(new_notes)
{
$.ajax({
type: "POST",
//dataType: "json",
url: '/pcg/popups/updateNotes.php',
data:
{
'nameNotes': notes_name.text(),
'newNotes': new_notes
},
success: function(response) {
alert("Notes Updated.");
var i;
$("#dialog-container").effect( 'fade', 500 );
i = setInterval(function(){
$("#dialog-container").dialog( 'close' );
clearInterval(i);
}, 500);
}
});
}
/******is user closes notes ******/
function closeNotes()
{
var i;
$("#dialog-container").effect( 'fade', 500 );
i = setInterval(function(){
$("#dialog-container").dialog( 'close' );
clearInterval(i);
}, 500);
}
Let me know if you need anything else!
UPDATE:
The basic layout is
<div>
<div>
other stuff...
the table
</div>
</div>
Assuming that #notes_msg is located in #dialog-container, you would have to make sure that the actions happen in the correct order.
The best way to do that, is to wait for both ajax calls to finish and continue then. You can do that using the promises / jqXHR objects that the ajax calls return, see this section of the manual.
You code would look something like (you'd have to test it...):
function run(){
var url = '/pcg/popups/grabnotes.php';
var tag = $("#dialog-container");
var promise1 = showUrlInDialog(url);
var promise2 = sendUserfNotes();
$.when(promise1, promise2).done(function(data1, data2) {
// do something with the data returned from both functions:
// check to see what data1 and data2 contain, possibly the content is found
// in data1[2].responseText and data2[2].responseText
// stuff from first ajax call
tag.html(data1).dialog({
width: '100%',
modal: true
}).dialog('open');
// stuff from second ajax call, will not fail because we just added the correct html
$('#notes_msg').text(data2.the_notes)
});
}
The functions you are calling, should just return the result of the ajax call and do not do anything else:
function showUrlInDialog(url)
{
return $.ajax({
url: url
});
}
function sendUserfNotes()
{
return $.ajax({
type: "POST",
dataType: "json",
url: '/pcg/popups/getNotes.php',
data: {
'nameNotes': notes_name.text()
}
});
}
It's hard to tell from this, especially without the mark up, but both showUrlInDialog and sendUserfNotes are asynchronous actions. If showUrlInDialog finished after sendUserfNotes, then showUrlInDialog overwrites the contents of the dialog container with the data returned. This may or may not overwrite what sendUserfNotes put inside #notes_msg - depending on how the markup is laid out. If that is the case, then it would explains why the notes sometimes do not appear, seemingly randomly. It's a race condition.
There are several ways you can chain your ajax calls to keep sendUserOfNotes() from completing before ShowUrlInDialog(). Try using .ajaxComplete()
jQuery.ajaxComplete
Another ajax chaining technique you can use is to put the next call in the return of the first. The following snippet should get you on track:
function ShowUrlInDialog(url){
$.get(url,function(data){
tag.html(data).dialog({width: '100%',modal: true}).dialog('open');
sendUserOfNotes();
});
}
function sendUserOfNotes(){
$.post('/pcg/popups/getNotes.php',{'nameNotes': notes_name.text()},function(response){
$('#notes_msg').text(response.the_notes)
},"json");
}
James has it right. ShowUrlInDialog() sets the dialog's html and sendUserOfNotes() changes an element's content within the dialog. Everytime sendUserOfNotes() comes back first ShowUrlInDialog() wipes out the notes. The promise example by jeroen should work too.
I have a simple toggle button that the user can use to either subscribe or unsubscribe from a group they belong to. I have 2 forms that get the post and depending on which page the form posts to, the user is subscribed or unsubscribed. Here's my code and I'm looking for a better way to do this. Currently, my user can click to subscribe or unsubscribe but he or she will have to reload the page to change their setting. In other words, it works fine but there's no toggle...users can't click back and forth between subscribe and unsubscribe, as they have to refresh the page and resubmit. I also would love to fix the toggle function. Thanks for any help.
<script type="text/javascript">
//Capturing get parameter
var param1var = getQueryVariable("group_id");
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}
}
var owner = getQueryVariable('group_id');
var dataString = "owner="+ owner;
$(function() {
$("#subscribe").click(function(){
$.ajax({
type: "POST",
url: "groupnotifications.php",
data: dataString,
success: function(){
$("#subscribe").removeClass("notifications_subsc");
$("#subscribe").addClass("not_subscribed_group");
}
});
});
});
</script>
<script type="text/javascript">
//Capturing get parameter
var param1var = getQueryVariable("group_id");
function getQueryVariable(variable) {
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if (pair[0] == variable) {
return pair[1];
}
}
}
var owner = getQueryVariable('group_id');
var dataString = "owner="+ owner;
$(function() {
$("#notsubscribed").click(function(){
$.ajax({
type: "POST",
url: "groupnotificationsoff.php",
data: dataString,
success: function(){
$("#notsubscribed").removeClass("not_subscribed_group");
$("#notsubscribed").addClass("notifications_subsc");
}
});
});
});
</script>
There's no need to rely on parsing out the query string when server-side scripting is available. Instead, when the page is initially served, arrange for PHP to write the group_id value into (eg.) a hidden input field, which then becomes available client-side to be read into javascript/jQuery. (Other techniques are available)
It's also a good idea to arrange for your "groupnotifications.php" script to receive a $_POST['action'] instruction to either subscribe or unsubscribe. That way the client-side half of the application exercises control.
With those changes in place, the code will be something like this:
$(function() {
$("#subscribe").click(function(){
var $s = $(this).attr('disabled',true);//disable button until ajax response received to prevent user clicking again
var clss = ['not_subscribed_group','notifications_subsc'];//The two classnames that are to be toggled.
var dataOj = {
owner : $s.closest(".groupContainer").find('.group_id').val(),//relating to element <input class="group_id" type="hidden" value="..." />
action : ($s.hasClass(clss[0])) ? 1 : 0;//Instruction to 1:subscribe or 0:unsubscribe
};
$.ajax({
type: "POST",
url: "groupnotifications.php",
data: dataObj,
success: function(status) {//status = 1:subscribed or 0:unsubscribed
switch(Number(status)){
case 1:
$s.removeClass(clss[1]).addClass(clss[0]);
break;
case 0:
$s.removeClass(clss[0]).addClass(clss[1]);
break;
default:
//display error message to user
}
}
error: function(){
//display error message to user
}
complete: function(){
$s.attr('disabled',false);
}
});
});
});
untested
Note: The statement $s.closest(".groupContainer").find('.group_id').val() relies on the hidden input element having class="group_id" and allows for multiple groups, each with its own toggle action, on the same page. Just make sure each group is wrapped in an element (eg div or td) with class="groupContainer".
I made a moderation script, voting up and down question and answers. Time ago the script worked, but when i came back to start coding in this project one more time, it doesn't work anymore.
The script was doing: when you click in a div called vote, or vote1 a link, it ask if it's up or down. If it's up, it loads url: "mod_up_vote.php" sending by post some info about the question you are voting on. It was ok. But not now. It doesn't load that page, because i was printing and inserting in database the $_POST variable and nothing was there.
What do you think is wrong here? Thanks.
$(document).ready(function()
{
$(document).delegate('.vote, .vote1', '.vote2', 'click', function()
{
var id = $(this).attr("id");
var name = $(this).attr("name");
var dataString = 'id='+ id ;
var parent = $(this);
if(name=='mod_up')
{
$(this).fadeIn(200).html('<img src="dot.gif" align="absmiddle">');
$.ajax({
type: "POST",
url: "mod_up_vote.php",
dataType: "xml",
data: dataString,
cache: false,
success: function(xml)
{
//$("#mod-pregunta").html(html);
//$("#mod-respuesta").html(html);
//parent.html(html);
$(xml).find('pregunta').each(function(){
var id = $(this).attr('id');
var pregunta = $(this).find('preguntadato').text();
var respuesta = $(this).find('respuestadato').text();
var votoup = $(this).find('votoup').text();
var votodown = $(this).find('votodown').text();
var id_pregunta = $(this).find('id_pregunta').text();
var id_respuesta = $(this).find('id_respuesta').text();
$("#mod-pregunta").html(pregunta);
$("#mod-respuesta").html(respuesta);
//$(".vote").attr('id', $(this).find('id_pregunta').text());
$(".vote1").html("Aceptar");
$(".vote2").html("Rechazar");
//$("span", this).html("(ID = '<b>" + this.id + "</b>')");
});
} });
}
return false;
});
This looks like a problem with your JQuery. Why are you using delegate instead of click? Also, your arguments to delegate appear to be incorrect. If you look at the documentation you'll see the function signature is:
$(elements).delegate(selector, events, data, handler); // jQuery 1.4.3+
You are binding your function to an event called '.vote2', which I can only assume does not exist.
Try using click instead, there's no reason to use delegate as far as I can tell.
edit:
Try using click like so:
$('.vote, .vote1').click(function(){ /* your code here */ });
I'm kinda new to jQuery but understand it for the most part. My problem is that when my ajax call which refreshes the entire div is done, all my dynamically created forms don't work. If you try and submit them, the event doens't work properly and just tries to do a normal form submit. I have all the other items such as links bound using the .live() which seem to work great. Just the form dies.
How do I rebind the dynamically created forms after the ajax call? They all have id of formname_id. I tried to use bind but it doesn't work as below. Any help is appreciated.
Here is the code
jQuery(document).ready(function(){
jQuery("form[id^='commentform_']").each(function(){
var id = parseInt(this.id.replace("commentform_", ""));
jQuery(this).bind('submit', function(e) {
var action = jQuery('#action_' + id).attr('value');
var act_id = ('1');
jQuery.ajax({
type: "POST",
url: "ajax/modify.php",
data: "action="+ action +"& act_id="+ act_id,
success: function(response){
jQuery('#CommentsContainer_' + id).html(response);
jQuery('#commentform_' + id)[0].reset();
}
});
return false;
});
});
});
Try doing something like this:
jQuery("form[id^='commentform_']").live('submit',function(){
var id = parseInt(this.id.replace("commentform_", ""));
var action = jQuery('#action_' + id).attr('value');
var act_id = ('1');
jQuery.ajax({
type: "POST",
url: "ajax/modify.php",
data: {"action": action, "act_id": act_id},
success: function(response){
jQuery('#CommentsContainer_' + id).html(response);
jQuery('#commentform_' + id)[0].reset();
}
});
return false;
});
No need to loop over the forms to bind to them. If you can use delegate instead of live do so.
Why don't you over-ride the normal form submit:
function addNewitem() {
$('#new_item_form').submit(function() {
$.get("includes/ItemEdit.php", {
newItem: true
},
function(msg) {
isNewItem = true;
$("#new_item").hide();
$('#item_list').hide();
$("#item_edit").html( msg );
$("#item_edit").show();
editActiveEvent();
});
return false;
});
}
Don't forget to return false. or do a .preventDefault
I have gotten this to work adding the event in the function call and using event.preventDefault(); BUT of course only in FF. Doesn't work in IE7..
jQuery("form[id^='commentform_']").live('submit',function(event){
var id = parseInt(this.id.replace("commentform_", ""));
var action = jQuery('#action_' + id).attr('value');
var act_id = ('1');
jQuery.ajax({
type: "POST",
url: "ajax/modify.php",
data: {"action": action, "act_id": act_id},
success: function(response){
jQuery('#CommentsContainer_' + id).html(response);
jQuery('#commentform_' + id)[0].reset();
}
});
event.preventDefault();});
But IE7 still tries to sumbit the action. arrgggh.. Anything I'm doing wrong??