jQuery removes first div only once - javascript

I have a function:
function removeDiv() {
var topmost = jQuery('.xx');
var totContent = topmost.find('.zz').length;
var $target = jQuery('.xx').find('.zz').eq(0);
if(totContent > 5) {
$target.hide('slow', function(){ $target.remove(); });
}
}
I use it in my ajax call, to remove extra div then there are more than 5, hovewer it remove first div only once!
And this is how ajax call looks:
function saveClubs(array) {
for(i=0; i<array.length; i++) {
var id = array[i];
jQuery.ajax({
type: "GET",
async: true,
url: 'index.php?option=com_events&task=club.save&id=' + id,
dataType: 'json',
success: function(data) {
jQuery('.xx').append('<div class="zz">'+data+'</div>');
removeDiv();
}
});
}
}
Any ideas ?

This is Paul Roub's answer, posted as an answer rather than a comment:
The likely problem is that since you're doing a bunch of ajax calls in a loop, they tend to complete at the same time, and so you end up repeated fading out the same element (since it's still there until it's done fading).
The minimal changes fix would be to, say, add a class as you're fading it out:
function removeDiv() {
// Get the container (I take it there's only one .xx element)
var topmost = jQuery('.xx');
// Get the child elements that aren't fading
var zz = topmost.find('.zz').not('.fading');
// Too many?
if(zz.length > 5) {
// Yup, add 'fading' to the first one and fade it out
// Note that there's no need for the $target variable
zz.eq(0).addClass('fading').hide('slow', function(){ $(this).remove(); });
}
}

The problem is this:
var $target = jQuery('.xx').find('.zz').eq(0);
It's always 0 index.
function removeDiv(x) {
var topmost = jQuery('.xx');
var totContent = topmost.find('.zz').length;
var $target = jQuery('.xx').find('.zz').eq(x);
if(totContent > 5) {
$target.hide('slow', function(){ $target.remove(); });
}
}
function saveClubs(array) {
for(i=0; i<array.length; i++) {
var id = array[i];
jQuery.ajax({
type: "GET",
async: true,
url: 'index.php?option=com_events&task=club.save&id=' + id,
dataType: 'json',
success: function(data) {
jQuery('.xx').append('<div class="zz">'+data+'</div>');
removeDiv(i);
}
});
}
}
LIVE EXAMPLE HERE
NOTE
IN the Fiddle above, try to change this var $target = jQuery('.xx').find('.zz').eq(x); harcoding the value of x to 0 and it'll happen just once.

Related

Javascript, make ajax call after 3 seconds

I have a working javascript block that basically takes user input, and upon each keystroke makes an Ajax POST call.
This works perfectly but I'd like to change it to only fire the ajax 3 seconds after the user starts typing, as opposed to every keystroke. Ideally I'd like to fire it after 3 seconds and if they start typing again it would start over, but the initial delay is most important.
I tried to do a set interval around it but it's didn't make the ajax call, so I'm wondering if there's different approach I need to take.
how can I make this ajax only call 3 seconds after typing in the input starts?
$('#productInput').on('input', function() {
let _this = $(this);
let optSelector = `option[value='${_this.val()}']`;
if (_this.val() === '') {
return;
} else if ($('#returnedProducts').find(optSelector).length) {
//html stuff
} else {
const searchResult = $(this).val();
$.ajax({ url: '/account/autocomplete',
data: {
search_result:searchResult
},
"_token": "{{ csrf_token() }}",
type: "POST",
success: function (response) {
$("#returnedProducts").empty();
var result = response.hits.hits;
for (let i = 0; i < result.length; i++) {
$("#returnedProducts").append($("<option/>",
{
//option stuff
}
));
}
}
});
}
});
Have a persistent variable that holds a setTimeout. On input, clear the current timeout (if there is one), and set another timeout to trigger in 3 seconds (unless another input event occurs). You may also consider putting the ajax call (at least) into its own function, for the sake of less indentation hell:
let timeout;
$('input').on('input', () => {
clearTimeout(timeout);
console.log('timeout set');
timeout = setTimeout(() => console.log('action running'), 3000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input>
let timeout;
$('#productInput').on('input', function() {
clearTimeout(timeout);
let _this = $(this);
let optSelector = `option[value='${_this.val()}']`;
if (_this.val() === '') {
return;
} else if ($('#returnedProducts').find(optSelector).length) {
//html stuff
} else {
const searchResult = $(this).val();
timeout = setTimeout(ajaxCall, 3000, searchResult);
}
});
function ajaxCall(search_result) {
$.ajax({
url: '/account/autocomplete',
data: { search_result },
"_token": "{{ csrf_token() }}",
type: "POST",
success: successHandler
});
}
function successHandler(response) {
$("#returnedProducts").empty();
var result = response.hits.hits;
for (let i = 0; i < result.length; i++) {
$("#returnedProducts").append($("<option/>", {
//option stuff
}));
}
}

Previous divs with jQuery does not work after Ajax call

I have two scripts:
The first one is image carousel. It uses jQuery slick slider.
The second one is an Ajax script that loads contents as page scrolls down.
Here is my code:
function slider () {
var $arrows = $('.arrows');
var $next = $arrows.children(".slick-next");
var $prev = $arrows.children(".slick-prev");
var slick = $('.your-class').slick({
appendArrows: $arrows
});
$('.slick-next').on('click', function (e) {
var i = $next.index( this )
slick.eq(i).slickNext();
});
$('.slick-prev').on('click', function (e) {
var i = $prev.index( this )
slick.eq(i).slickPrev();
});
}
$(document).ajaxComplete(slider);
Below is the scroll content load with Ajax:
$(document).ready(function(){
function slider () {
var $arrows = $('.arrows');
var $next = $arrows.children(".slick-next");
var $prev = $arrows.children(".slick-prev");
var slick = $('.your-class').slick({
appendArrows: $arrows
});
$('.slick-next').on('click', function (e) {
var i = $next.index( this )
slick.eq(i).slickNext();
});
$('.slick-prev').on('click', function (e) {
var i = $prev.index( this )
slick.eq(i).slickPrev();
});
}
$(document).ajaxComplete(slider);
var flag = 0;
$.ajax({
type: "GET",
url: "getdata.php",
data: {
'offset': 0,
'limit': 10
},
success: function(data){
$('.rowmasonry').append(data);
flag += 10;
},
});
$(window).scroll(function(){
if($(window).scrollTop() >= $(document).height() - $(window).height()-500){
$.ajax({
type: "GET",
url: "getdata.php",
data: {
'offset': flag,
'limit': 10
},
success: function(data){
$('.rowmasonry').append(data);
flag += 10;
},
});
}
});
});
The problem is that the first 10 contents that are loaded work properly. However, as I scroll down, and another 10 contents come, the first 10 contents that were loaded do not respond.
How do I bind the image slider to Ajax, so that all contents on the page work with jQuery?
Thanks for your help.
You are just appending new elements to DOM. In order to update slick you need to reInit slick carousel or if you are sure about the slide markup then you can use slickAdd method provided by plugin.
$.ajax().done(function(data){
$('.your-class').slick('slickAdd', data);
});
ref: http://kenwheeler.github.io/slick/

Adding event handler to non-existent class?

I've seen questions that relate to non-existent elements, but not non-existent classes. Here's what I want to do. When a button of class "see_answer" is clicked, I want to remove the class and replace it with "see_question". However, my click function for a button, once its class is "see_question", is not running. I have tried $(document).on("click", ".see_question", function(event ) and I have tried $(".see_question").on("click", function(event) {etc.... Thanks for the help! My code is below:
$(document).ready(function() {
// initialize variables
var lang = "javascript";
var qno = 1;
var prevText; // holds question/answer
var language = lang + ".html";
// set up tabs, and keep track of which one is clicked
$("#myTabs").tabs({
activate: function (event, ui) {
var active = $("#myTabs").tabs("option", "active");
lang = $("#myTabs ul > li a").eq(active).attr("href");
lang = lang.replace("#", "");
}
});
/* REMINDERS
actual qa part: blah_language
*/
// set up question
$.ajax({
url: language,
dataType: "html",
success: function(data) {
$("#blah_"+lang)
.text($(data).find("#1").text());
},
error: function(r) {
alert("whoops, error in initialization");
}
});
$(".next_question").on("click", function(event) {
event.preventDefault();
var id = $(this).attr("id").replace("next_question_", "");
var language = id + ".html";
var doc = "#blah_" + id;
$.ajax({
url: language,
dataType: "html",
success: function(data) {
var num = "#" + qno;
$(doc)
.text($(data).find(num).text());
qno = qno + 1;
},
error: function(r) {
alert("whoops");
}
});
prevText = "";
});
// SHOW ANSWER
$(".see_answer").on("click", function(event) {
event.preventDefault();
var id = $(this).attr("id").replace("see_answer_", "");
var prev = "#blah_" + id;
var answers = id + "_answers.html";
// Save the question
prevText = $(prev).text();
var obj = $(this);
$.ajax({
url: answers,
dataType: "html",
success: function(data) {
var num = "#" + 3;
$(prev)
.text($(data).find(num).text());
},
error: function(r) {
alert("whoops");
}
});
obj.val("See Question");
obj.removeClass("see_answer");
obj.addClass("see_question");
event.stopPropagation();
});
$(document).on("click",".see_question", function(event) {
event.preventDefault();
obj = $(this);
event.preventDefault();
var id = $(this).attr("id").replace("see_answer_", "");
var prev = "#blah_" + id;
$(prev).text(prevText);
obj.val("See Answer");
obj.removeClass("see_question");
obj.addClass("see_answer");
});
})
Click handling for .see_question elements is delegated to document. For .see_answer elements, a click handler is attached directly. Therefore, swapping the class names will have an undesirable effect.
when see_answer is in force, a click will trigger the "see_answer" handler.
when see_question is in force, a click will trigger the "see_question" handler AND the "see_answer" handler, which is still attached.
There's a number of ways to do this properly. From where you currently are, the simplest solution is to delegate click handling of .see_question and .see_answer elements to document.
$(document).on("click", ".see_answer", function(event) {
...
});
$(document).on("click", ".see_question", function(event) {
...
});
Combine the 2 handlers and figure out which version it is by hasClass() before you change the classes around
$(document).on("click", ".see_question, .see-answer", function(event ){
var $btn =$(this), isAnswer = $btn.hasClass('see_answer');
// we know which one it is so can switch classes now
$btn.toggleClass('see_answer see_question');
if(isAnswer){
/* run code for answer version */
}else{
/* run code for question version */
}
});

2 javascripts are conflicting

I have 2 javascripts that are conflicting with eachother, the newer one (Zeroclipboard) conflicts with the older one (delete row) and won't let the delete row one work. The moment i removed the zeroclipboard one, delete worked.
Tried adding jQuery.noConflict(); but didn't seem to work. By reading few solutions, I decided to remove $ signs, but still no.
I have a files.php file, including the header.php file. I am adding the custom.js file in header.php, which holds many functions for operations across the project, including the delete row function. Whereas, the newer script for ZerClipboard is in files.php itself.
Older one, to delete a table row on delete icon click, which won't work after I add the next:
custom.js
function deleteRow()
{
var current = window.event.srcElement;
while ( (current = current.parentElement) && current.tagName !="TR");
current.parentElement.removeChild(current);
}
$(document).ready(function()
{
$('table#delTable td a.delete').click(function()
{
if (confirm("Are you sure you want to delete?"))
{
var fid = $(this).parent().parent().attr('fid');
var str=$(this).attr('rel');
var data = 'fid=' + $(this).attr('rel') + '&uid=' + $(this).parent().attr('rel');
var deletethis = '#tr' + $(this).attr('rel');
var parent = $(this).parent().parent();
$.ajax(
{
type: "POST",
url: "delete.php",
data: data,
cache: false,
success: function(msg)
{
$(deletethis).fadeOut('slow', function() {$(this).remove();});
}
});
}
});
$('table#delTable tr:odd').css('background',' #FFFFFF');
});
ZeroClipboard's JS and SWF, along with this js to copy some text on clipboard on Share icon click:
files.php
<script type="text/javascript" src="js/ZeroClipboard.js"></script>
<script language="JavaScript">
var clip = null;
function $(id) { return document.getElementById(id); }
function init()
{
clip = new ZeroClipboard.Client();
clip.setHandCursor( true );
}
function move_swf(ee)
{
copything = document.getElementById(ee.id+"_text").value;
clip.setText(copything);
if (clip.div)
{
clip.receiveEvent('mouseout', null);
clip.reposition(ee.id); }
else{ clip.glue(ee.id); }
clip.receiveEvent('mouseover', null);
}
</script>
I used this blog post for implementing multiple zerclipboard - http://blog.aajit.com/easy-multiple-copy-to-clipboard-by-zeroclipboard/
And, here's the HTML source generated by the files.php page - http://jpst.it/tlGU
Remove the follow function definition of your second script:
function $(id) { return document.getElementById(id); }
Because this is redefining your $ object in window context, due when you use $ in your first script you're not using jquery, instead you're using your new function definition.
Hope this helps,
Here is how you should use noConflict() :
function deleteRow()
{
var current = window.event.srcElement;
while ( (current = current.parentElement) && current.tagName !="TR");
current.parentElement.removeChild(current);
}
jQuery.noConflict(); // Reinitiating $ to its previous state
jQuery(document).ready(function($) // "Protected" jQuery code : $ is referencing jQuery inside this function, but not necessarily outside
{
$('table#delTable td a.delete').click(function()
{
if (confirm("Are you sure you want to delete?"))
{
var fid = $(this).parent().parent().attr('fid');
var str=$(this).attr('rel');
var data = 'fid=' + $(this).attr('rel') + '&uid=' + $(this).parent().attr('rel');
var deletethis = '#tr' + $(this).attr('rel');
var parent = $(this).parent().parent();
$.ajax(
{
type: "POST",
url: "delete.php",
data: data,
cache: false,
success: function(msg)
{
$(deletethis).fadeOut('slow', function() {$(this).remove();});
}
});
}
});
$('table#delTable tr:odd').css('background',' #FFFFFF');
});
And in files.php:
<script src="js/ZeroClipboard.js"></script>
<script>
var clip = null;
function $(id) {
return document.getElementById(id);
}
function init() {
clip = new ZeroClipboard.Client();
clip.setHandCursor(true);
}
function move_swf(ee) {
copything = document.getElementById(ee.id + "_text").value;
clip.setText(copything);
if (clip.div) {
clip.receiveEvent('mouseout', null);
clip.reposition(ee.id);
} else {
clip.glue(ee.id);
}
clip.receiveEvent('mouseover', null);
}
</script>

jQuery on or live?

I recently deployed an infinite scroll to an app that I have build and found that sometimes I need to click twice for something to happen.
My app has likes, and once the dom had loaded, i need to click on the like button twice before it changes, then once i click on the other ones it's okay but I always have to click once for the app to almost "wake up"
Is there a better solution?
$(document).ready(function() {
function runUpdate(url, item) {
$.ajax({
type: "GET",
url: url,
cache: false,
success: function(data){
if (data == '200') {
removeAddColor(item);
}
}
});
}
$('.mini-like').live('click', function(){
$('.mini-like').toggle(
function() {
var item = $(this);
var href = item.attr('href');
runUpdate(href, item);
},
function() {
var item = $(this);
var rel = item.attr('rel');
runUpdate(rel, item);
}
);
});
function removeAddColorFollow(item) {
var href = $(this).attr('href');
var rel = $(this).attr('rel');
if (item.hasClass('btn-success')) {
$(item).removeClass('btn-success').attr('href', href).attr('rel', rel);
$(item).find('i').removeClass('icon-white');
} else {
$(item).addClass('btn-success').attr('href', rel).attr('rel', href);
$(item).find('i').addClass('icon-white');
};
}
});
Well unless I'm completely wrong, you only attach the toggle event to .mini-like after it has been clicked once. Try to just replace
$('.mini-like').live('click', function() {...
With
$(function() {...
To attach the toggle event handler on document ready instead of on click
The code $('.mini-like').live('click',... should be placed inside $(document).ready()
You can use .on in place of .live. As .on is a new method and .live is deprecated now you should use .on
UPDATE
The re-written version will be
$(document).ready(function(){
$('.mini-like').on('click', function(){
$('.mini-like').toggle(
function() {
var item = $(this);
var href = item.attr('href');
runUpdate(href, item);
},
function() {
var item = $(this);
var rel = item.attr('rel');
runUpdate(rel, item);
}
);
});
});
function runUpdate(url, item) {
$.ajax({
type: "GET",
url: url,
cache: false,
success: function(data){
if (data == '200') {
removeAddColor(item);
}
}
});
}
function removeAddColorFollow(item) {
var href = $(this).attr('href');
var rel = $(this).attr('rel');
if (item.hasClass('btn-success')) {
$(item).removeClass('btn-success').attr('href', href).attr('rel', rel);
$(item).find('i').removeClass('icon-white');
} else {
$(item).addClass('btn-success').attr('href', rel).attr('rel', href);
$(item).find('i').addClass('icon-white');
};
}

Categories

Resources