How would I loop this? - javascript

I am trying to loop functionality for buttons I've made. I have 3 video collections. and they all need the same script for next and previous.
What I want is that I only have to make one next button and one prev button.
This is what it should do:
$("#next-1").click(function(){
var $this = $(".video-album-1");
callback = function() {
$this.insertBefore($this.siblings(':eq(2)'));
}
$this.fadeOut(200, callback).fadeIn(400);
});
$("#prev-1").click(function(){
var $this = $(".video-album-1");
callback = function() {
$this.insertAfter($this.siblings(':eq(3)'));
}
$this.fadeOut(200, callback).fadeIn(400);
});
$("#next-2").click(function(){
var $this = $(".video-album-2");
callback = function() {
$this.insertBefore($this.siblings(':eq(2)'));
}
$this.fadeOut(200, callback).fadeIn(400);
});
$("#prev-2").click(function(){
var $this = $(".video-album-2");
callback = function() {
$this.insertAfter($this.siblings(':eq(3)'));
}
$this.fadeOut(200, callback).fadeIn(400);
});
I've already tried to loop it, but this doesn't work:
for (i = 0; i < 3; i++) {
$("#next-"+i).click(function(){
var $this = $(".video-album-"+i);
callback = function() {
$this.insertBefore($this.siblings(':eq(2)'));
}
$this.fadeOut(200, callback).fadeIn(400);
});
$("#prev-"+i).click(function(){
var $this = $(".video-album-"+i);
callback = function() {
$this.insertAfter($this.siblings(':eq(3)'));
}
$this.fadeOut(200, callback).fadeIn(400);
});
}
Is there anyone that could tell me a solution? I do not want to repeatedly create #next-3 #next-4 ids etc..
Thanks in advance.

Can you take a look at below approach:
$("[id^=next-]").click(function(){
var current_id = $(this).attr("id");
var number = current_id.replace("next-","");
var $this = $(".video-album-"+number);
callback = function() {
$this.insertBefore($this.siblings(':eq(2)'));
}
$this.fadeOut(200, callback).fadeIn(400);
});
$("[id^=prev-]").click(function(){
var current_id = $(this).attr("id");
var number = current_id.replace("prev-","");
var $this = $(".video-album-"+number);
callback = function() {
$this.insertAfter($this.siblings(':eq(3)'));
}
$this.fadeOut(200, callback).fadeIn(400);
});
Here we are using jQuery's starts with selector to attach the event to required DOM elements and within event handler we are grabbing the associated number for further process.

Use a class with next(),prev(),find() to get the video album class based on the next/prev elements or use this hack
$('[id^="next-"]').click(function(){
var i = $(this).attr('id').split('-')[1];
var $this = $(".video-album-"+i);
callback = function() {
$this.insertBefore($this.siblings(':eq(2)'));
}
$this.fadeOut(200, callback).fadeIn(400);
});
$('[id^="prev-"]').click(function(){
var i = $(this).attr('id').split('-')[1];
var $this = $(".video-album-"+i);
callback = function() {
$this.insertAfter($this.siblings(':eq(3)'));
}
$this.fadeOut(200, callback).fadeIn(400);

I'll emphasize now this is just one way, there might be better ones
Assuming these are your buttons
<button class="next" data-videocollectionname="video1">next</button>
<button class="next" data-videocollectionname="video2">next</button>
<button class="next" data-videocollectionname="video3">next</button>
<button class="previous" data-videocollectionname="video1">previous</button>
<button class="previous" data-videocollectionname="video2">previous</button>
<button class="previous" data-videocollectionname="video3">previous</button>
I've given each button a data attribute to say which collection the button is relevant too.
Forgive me if I've miss understood the question
$(".next").click(function(){
var videoCollectionName = $(this).data("videocollectionname");
var videoElement = $("#"+videoCollectionName);
//do whatever code you want for the videocollection
});
$(".previous").click(function(){
var videoCollectionName = $(this).data("videocollectionname");
var videoElement = $("#"+videoCollectionName);
//do whatever code you want for the videocollection
});

This question and its answers explain why your attempt didn't work correctly.
Based on your attempted for loop, this will work:
$("[id^=next-]").click(function() {
var i = this.id.substring(5);
var album = $(".video-album-" + i);
callback = function() {
album.insertBefore(album.siblings(':eq(2)'));
};
album.fadeOut(200, callback).fadeIn(400);
});
$("[id^=prev-]").click(function() {
var i = this.id.substring(5);
var album = $(".video-album-" + i);
callback = function() {
album.insertAfter(album.siblings(':eq(3)'));
};
album.fadeOut(200, callback).fadeIn(400);
});
That works by using an attribute starts with selector to match all of your next- (and prev-) buttons, then figures out the index from the id of the button actually clicked.
But there's probably a better answer we could give you if you quote your HTML.

Related

jQuery click inside each loop

I want to loop my click events, to make the code shorter. I might have 30 of these values later on.
My working code
$(document).ready(function () {
var last_click = '';
$("#title").click(function() { last_click = 'title'; });
$("#subtitle").click(function() { last_click = 'subtitle'; });
$("#test").click(function() { last_click = 'test'; });
});
This is how I want it (not working)
My guess is that the each-loop runs on dom ready and then never again and that way the click-event can never be triggered?
$(document).ready(function () {
var last_click = '';
var contents = new Array();
contents = ['title', 'subtitle', 'test'];
$.each(contents , function(index, value){
$("#" + value).click(function() { last_click = value; });
});
});
If there is not solved like I would, I would be thankful for a nice workaround.
I would rather add a class to all elements you want to bind this to, eg class="last-click"
and define the binding once as:
$(".last-click").on('click', function() {
last_click = this.id;
}
If you really wanted to make it shorter, give them all a similar class.
$(document).ready(function () {
var last_click = '';
$(".theclass").click(function() {
last_click = this.id;
});
});
if you have value attribute for your buttons or elements, you can do it:
$(document).ready(function() {
var last_click = '';
$("input").click(function() {
last_click = $(this).attr('value');
alert(last_click);
});
});​
I assumed that you are using "input type="button". Also here is the demo you can see it in action: http://jsfiddle.net/rS2Gb/5/

refactor this javascript code

I have two click-events, that are nearly similar, but not quite. I am wondering how to refactor them best:
$('.remove_fields.dynamic').live('click', function(e) {
var $this = $(this);
var after_removal_trigger_node = $this.closest(".nested-fields").parent();
trigger_removal_callback($this);
e.preventDefault();
$this.closest(".nested-fields").remove();
trigger_after_removal_callback(after_removal_trigger_node);
});
$('.remove_fields.existing').live('click', function(e) {
var $this = $(this);
var after_removal_trigger_node = $this.closest(".nested-fields").parent();
trigger_removal_callback($this);
e.preventDefault();
$this.prev("input[type=hidden]").val("1");
$this.closest(".nested-fields").hide();
trigger_after_removal_callback(after_removal_trigger_node);
});
As you can tell there is a fair bit of overlap. I am wondering what the best/nicest way would be to refactor this code.
Do a class check in the .remove_fields click function.
$('.remove_fields').click(function(e) {
var $this = $(this);
var after_removal_trigger_node = $this.closest(".nested-fields").parent();
trigger_removal_callback($this);
e.preventDefault();
if($this.hasClass("dynamic") {
$this.closest(".nested-fields").remove();
} else if($this.hasClass("existing")) {
$this.prev("input[type=hidden]").val("1");
$this.closest(".nested-fields").hide();
}
trigger_after_removal_callback(after_removal_trigger_node);
});
Combine the selectors into $('.remove_fields.dynamic, .remove_fields.existing').
Then, test if $this has class existing. If so, run $this.prev("input[type=hidden]").val("1");.
Done.
taking cleaning a bit more:
$('.remove_fields').click(function(e) {
e.preventDefault();
var $this = $(this);
var $nestedFields = $this.closest(".nested-fields");
trigger_removal_callback($this);
if($this.hasClass("dynamic") {
$nestedFields.remove();
} else if($this.hasClass("existing")) {
$this.prev("input[type=hidden]").val("1");
$nestedFields.hide();
}
trigger_after_removal_callback($nestedFields.parent());
});

Toggling two events on one button

I'm trying to add some functionality to be able to edit comments inline. So far it's pretty close, but I'm experiencing issues trying to trigger a second event. It works the first time, but after that, fails.
$(function() {
var $editBtn = $('.js-edit-comment-btn');
var clicked = false;
$editBtn.on('click', $editBtn, function() {
clicked = true;
var $that = $(this);
var $form = $that.closest('.js-edit-comment');
var $commentTextBody = $that.closest('div').find('.js-comment-body');
var commentText = $commentTextBody.text();
var $editableText = $('<textarea />');
if ($that.text() === 'Save Edits') {
$that.text('Saving...').attr('disabled', true);
} else {
$that.text('Save Edits').attr('alt', 'Save your edits');
}
// Replace div with textarea, and populate it with the comment text
var makeDivTextarea = function($editableText, commentText, $commentTextBody) {
$editableText.val(commentText);
$commentTextBody.replaceWith($editableText);
$editableText.addClass('gray_textarea js-edited-comment').width('100%').css('padding', '4px').focus();
};
makeDivTextarea($editableText, commentText, $commentTextBody);
var saveEdits = function($that, $editableText) {
$that.on('click', $that, function() {
if (clicked) {
var comment = $that.closest('div').find('.js-edited-comment').val();
$editableText.wrap('<div class="js-comment-body" />').replaceWith(comment);
$that.text('Edit').attr('alt', 'Edit Your Comment').attr('disabled', false);
$('#output').append('saved');
clicked = false;
return false;
}
});
};
saveEdits($that, $editableText);
return false;
});
});​
jsfiddle demo here
Hiya demo for your working solution: http://jsfiddle.net/8P6uz/
clicked=true was the issue :)) I have rectified another small thing. i.e. $('#output') is set to empty before appending another saved hence text **saved** will only appear once.
small note: If I may suggest use Id of the button or if there are many edit buttons try using this which you already i reckon; I will see if I can write this more cleaner but that will be sometime latter-ish but this should fix your issue. :) enjoy!
Jquery Code
$(function() {
var $editBtn = $('.js-edit-comment-btn');
var clicked = false;
$editBtn.on('click', $editBtn, function() {
clicked = true;
var $that = $(this);
var $form = $that.closest('.js-edit-comment');
var $commentTextBody = $that.closest('div').find('.js-comment-body');
var commentText = $commentTextBody.text();
var $editableText = $('<textarea />');
if ($that.text() === 'Save Edits') {
$that.text('Saving...').attr('disabled', true);
} else {
$that.text('Save Edits').attr('alt', 'Save your edits');
}
// Replace div with textarea, and populate it with the comment text
var makeDivTextarea = function($editableText, commentText, $commentTextBody) {
$editableText.val(commentText);
$commentTextBody.replaceWith($editableText);
$editableText.addClass('gray_textarea js-edited-comment').width('100%').css('padding', '4px').focus();
};
makeDivTextarea($editableText, commentText, $commentTextBody);
var saveEdits = function($that, $editableText) {
$that.on('click', $that, function() {
if (clicked) {
var comment = $that.closest('div').find('.js-edited-comment').val();
$editableText.wrap('<div class="js-comment-body" />').replaceWith(comment);
$that.text('Edit').attr('alt', 'Edit Your Comment').attr('disabled', false);
$('#output').text("");
$('#output').append('saved');
clicked = true;
return false;
}
});
};
saveEdits($that, $editableText);
return false;
});
});​

jQuery + Javascript: Consolidate duplicate functions between document.ready and ajax load

I am using the ajaxify.js plugin https://github.com/browserstate/ajaxify to load content dynamically.
I have a number of click functions that I bind on document ready, but have to additionally put those functions inside of my ajax load function to re-bind the click events to the newly added content. I had tried using a single set of live functions previously but they didn't work.
Anyway I have the following code twice, once inside of a document.ready(function(){ }) and once again inside of ajaxify.js after the content loads.
I know it's superfluous, but I'm not sure of how to go about writing the functions just once so I can "include" them elsewhere. How can I optimize these functions so I can consolidate them and use them over again in an efficient manner?
Thank you!
var $filterclear = $('.filters .filter-clear'),
filtercount = $filterclear.length,
$searchedfor = $('.searched-for'),
is_search = $searchedfor.length;
$filterclear.bind('click', function(){
var $me = $(this);
if(filtercount == 3) {
$('.clear-all.filter-clear').addClass('filter-out').fadeOut('fast');
$(this).addClass('filter-out').fadeOut('fast');
} else {
$(this).addClass('filter-out').fadeOut('fast');
}
if($me.hasClass('clear-all') || filtercount == 1) {
$filterclear.addClass('filter-out').fadeOut('fast');
if(is_search !== 0) {
$('.filters').fadeOut();
}
}
});
$('.tag.remove-term').bind('click', function(){
var $me = $(this),
mytext = $me.text(),
$myfilter = $('.filters .filter-clear:contains("'+ mytext +'")');
if(filtercount == 3) {
$('.clear-all.filter-clear').addClass('filter-out').fadeOut('fast');
$myfilter.addClass('filter-out').fadeOut('fast');
} else {
$myfilter.addClass('filter-out').fadeOut('fast');
}
});
$searchedfor.find('.filter-clear').bind('click',function(){
$searchedfor.fadeOut();
});
Defining a new function should work (I didn't test it):
var $filterclear = $('.filters .filter-clear'),
filtercount = $filterclear.length,
$searchedfor = $('.searched-for'),
is_search = $searchedfor.length;
var doSomething($myfilter) {
if(filtercount == 3) {
$('.clear-all.filter-clear').addClass('filter-out').fadeOut('fast');
}
$myfilter.addClass('filter-out').fadeOut('fast');
};
$filterclear.bind('click', function() {
var $me = $(this);
doSomething($me);
if($me.hasClass('clear-all') || filtercount == 1) {
$filterclear.addClass('filter-out').fadeOut('fast');
if(is_search !== 0) {
$('.filters').fadeOut();
}
}
});
$('.tag.remove-term').bind('click', function(){
var $me = $(this),
mytext = $me.text(),
$myfilter = $('.filters .filter-clear:contains("'+ mytext +'")');
doSomething($me);
});
$searchedfor.find('.filter-clear').bind('click',function(){
$searchedfor.fadeOut();
});

How to detect if some text box is changed via external script?

I have some jQuery plugin that changes some elements, i need some event or jQuery plugin that trigger an event when some text input value changed.
I've downloaded jquery.textchange plugin, it is a good plugin but doesn't detect changes via external source.
#MSS -- Alright, this is a kludge but it works:
When I call boxWatcher() I set the value to 3,000 but you'd need to do it much more often, like maybe 100 or 300.
http://jsfiddle.net/N9zBA/8/
var theOldContent = $('#theID').val().trim();
var theNewContent = "";
function boxWatcher(milSecondsBetweenChecks) {
var theLoop = setInterval(function() {
theNewContent = $('#theID').val().trim();
if (theOldContent == theNewContent) {
return; //no change
}
clearInterval(theLoop);//stop looping
handleContentChange();
}, milSecondsBetweenChecks);
};
function handleContentChange() {
alert('content has changed');
//restart boxWatcher
theOldContent = theNewContent;//reset theOldContent
boxWatcher(3000);//3000 is about 3 seconds
}
function buttonClick() {
$('#theID').value = 'asd;lfikjasd;fkj';
}
$(document).ready(function() {
boxWatcher(3000);
})
try to set the old value into a global variable then fire onkeypress event on your text input and compare between old and new values of it. some thing like that
var oldvlaue = $('#myInput').val();
$('#myInput').keyup(function(){
if(oldvlaue!=$('#myInput').val().trim())
{
alert('text has been changed');
}
});
you test this example here
Edit
try to add an EventListner to your text input, I don't know more about it but you can check this Post it may help
Thanks to #Darin because of his/her solution I've marked as the answer, but i have made some small jQuery plugin to achieve the same work named 'txtChgMon'.
(function ($) {
$.fn.txtChgMon = function (func) {
var res = this.each(function () {
txts[0] = { t: this, f: func, oldT: $(this).val(), newT: '' };
});
if (!watchStarted) {
boxWatcher(200);
}
return res;
};
})(jQuery);
var txts = [];
var watchStarted = false;
function boxWatcher(milSecondsBetweenChecks) {
watchStarted = true;
var theLoop = setInterval(function () {
for (var i = 0; i < txts.length; i++) {
txts[i].newT = $(txts[i].t).val();
if (txts[i].newT == txts[i].oldT) {
return; //no change
}
clearInterval(theLoop); //stop looping
txts[i].f(txts[i], txts[i].oldT, txts[i].newT);
txts[i].oldT = $(txts[i].t).val();
boxWatcher(milSecondsBetweenChecks);
return;
}
}, milSecondsBetweenChecks);
}

Categories