dynamic attachment of event handler not working - javascript

I was just trying a small experiment in js. It's something like this; I have a ul and below that about 5 li, now I attach an event handler for click on the 1st li , using a selector like below:
var elem = $('ul li:nth-child('+ i +')');
Now I add the function funk, like so:
var funk = function() {
return i < 5 ? i++ : i = 0 ;
}
Now what I want to happen is once the first li is clicked, I want the event handler to be attached to the next li, and when I click on the li, the click event should be attached to the li after that and so on ...
Now I have written the following code so far:
var i = 0;
$('document').ready(function(){
str = funk();
console.log(str);
var elem = $('ul li:nth-child('+ i +')');
elem.on('click' , function(){
console.log('logged');
funk();
});
});
var funk = function() {
return i < 5 ? i++ : i = 0 ;
}
Now there are some obvious errors in the code that I am not able to iron out, for some reason the funk() function itself does't function as the I is never incremented.
Can somebody help me attach a dynamic event handler?
FIDDLE HERE
Ae-x.

Your code is correct, the problem is with declaration. Move func definition before it gets called.
The problem is with func function. It is a variable, so it gets declared initially and set to undefined, then all lines will gets executed but func is undefined so it will throw error.

I have created a recursive solution for same. This adds handlers for next list items only on click
$(document).ready(function() {
var i = 1;
addEventHandlerForNextItem(i);
function addEventHandlerForNextItem(num) {
var elem = $('ul li:nth-child(' + num + ')');
elem.on('click', function() {
console.log('element:' + elem[0].textContent);
alert('element:' + elem[0].textContent);
i = i + 1;
addEventHandlerForNextItem(i);
});
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>

not the prittest, but heres how i managed to attached the event handler dynamically ::
var i = 1;
var funk = function() {
return i < 5 ? ++i : i = 1 ;
}
changeHanderler = function(){
str = funk();
console.log(str);
var elem = $('ul li:nth-child('+ i +')');
elem.on('click.ga' , function(){
console.log('logged');
elem.off('click.ga');
changeHanderler();
});
}
$('document').ready(function(){
elem = $('ul li:nth-child('+ i +')');
elem.on('click.ga' , function(){
changeHanderler();
console.log('logged');
elem.off('click.ga');
});
});
not pritty but effective , also excessive usage of on() and off() jquery functions , maybe should have gone for the one() function.

Related

Assign value of the button to global variables on click, declared outside of the function

var x=0;
$(document).ready(function() {
$("div button").on("click", function(event) {
x = $(this).html();
}) ;
}) ;
console.log(x);
I have 5 buttons inside a div element I want the value of fhe button on click whrn they clicked by assigning it to a variable at outside of the function.
So.. Erm.. What you want to do is.. When Button X is clicked, you want to use the X value as an Index in Arr[X] to display the contens of that in the LST block?
Since you are pulling the data as html, which is like a string of sorts, you need to do a cast to int first before using it as such, I guess.
It would probably be better to add the value as a property so you can write something else than a number on the button..
And don't forget that arrays count from 0, and your buttons count from 1, so you would need to subtract 1 to get the first element of arr. Or you could just add an empty element to your arr like:
var arr = [{rId:0, hNo:""}, ...
// In which case you wouldn't need to subtract 1.
In any case on point with your current line, it would be:
$('div button').click(function (event) {
var x = parseInt($(this).html()) - 1;
$('#lst').html(arr[x].rId + " " + arr[x].hNo);
});
If you were going to use the value of button it would be like:
HTML:
<button value='1'>Click this amazing button that blows your mind..</button>
Script:
$('div button').click(function () {
var x = $(this).val();
$('#lst').html(arr[x].rId + " " + arr[x].hNo);
});
If I got you right, that is.
When you correct all the small spelling errors then code actually works fine, as you can see I've moved the console.log(x) inside your function so you can actually see that x is being set.
Var x=0; => var x=0;
$document. Ready(function() { => $(document).ready(function() {
$("div button"). On("click", function(event) { => $("div button").on("click", function(event) {
Console.log(x); => console.log(x);
var x = 0;
$(document).ready(function() {
$("div button").on("click", function(event) {
x = $(this).html();
console.log(x);
});
});
Note: if you are having problems getting the value of x outside the click function, then you need to provide us with more information about what you want to do with it or show us more of your jquery code.
demo
var x = 0;
var arr = [{rId: 1,hNo:"A31"},{rId: 2,hNo:"A32"},{rId: 2,hNo:"A33"}]
$(document).ready(function() {
$("div button").on("click", function(event) {
x = $(this).text().replace("button","");
document.getElementById("First").innerHTML = arr[x] != undefined ? arr[x].rId + " " + arr[x].hNo : "";
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<button>button1</button>
<button>button2</button>
<button>button3</button>
<button>button4</button>
<button>button5</button>
</div>
<div id="First"></div>

Click event object tracking woes

So I am working on this but of jQuery that gets the element id through a click event. This then triggers a function that acts like the deprecated .toggle()- it slides an element down on the fist click and slides that element up on the second click. However, there is a bug that causes the element to slide up and down the amount of times that it has been clicked on. For instance, if this is the second time I use the .clickToggle function, the element (table) slides up and down twice before settling, and so on. I suspect it has something to do with the event object, e, tracking the number of clicks-- i.e. I probably shouldn't set id = e.target.id-- but I'm not sure how to fix while still getting the relevant element id that I need.
Here is the relevant clickToggle plug in (courtesy of an answer here on stackoverflow).
(function($) {
$.fn.clickToggle = function(func1, func2) {
var funcs = [func1, func2];
this.data('toggleclicked', 0);
this.click(function() {
var data = $(this).data();
var tc = data.toggleclicked;
$.proxy(funcs[tc], this)();
data.toggleclicked = (tc + 1) % 2;
});
return this;
};
}(jQuery));
Here is the buggy code that fits the above description.
$(document).click(function(e) {
//get the mouse info, and parse out the relevant generated div num
var id = e.target.id;
var strId = id.match(/\d$/);
//clickToggle the individual table
$('#showTable' + strId).clickToggle(function () {
$('#table' + strId).slideDown();
$('#table' + strId).load('files.php');
},
function () {
$('#table' + strId).slideUp();
});
});//close mousemove function
Any help would be much appreciated. Thanks.
The problem is that you're registering a new click handler for the element each time you invoke clickToggle:
this.click(function() {...
On each subsequent click, you add another handler, as well as invoking all previous handlers. Bleagh.
Better to be straightforward: (DEMO)
var showTable = function($table) {
$table.slideDown();
$table.load('files.php');
$table.removeClass('hidden');
};
var hideTable = function($table) {
$table.slideUp();
$table.addClass('hidden');
};
$(document).click(function (e) {
//get the mouse info, and parse out the relevant generated div num
var id = e.target.id;
var strId = id.match(/\d$/)[0];
var $table = $('#table' + strId);
if ($table.hasClass('hidden')) {
showTable($table);
} else {
hideTable($table);
}
});

jQuery html() working witn alert in loop

I am using this code :-
function makeDirectionTabs() {
alert('sdfsf');
jQuery('.adp-warnbox').remove();
jQuery('#adp-placemark').parent().remove();
jQuery('.adp-legal').remove();
var i = 0;
jQuery('#fullDirections .adp > div').each(function () {
i = i + 1;
alert(i + jQuery(this).html());
directionContent = jQuery(this).html();
jQuery('#tab' + i).append(directionContent)
});
}
I got div elements in tab1 , tab2 etc.. with alert
But when I remove alert from this code I did not get div elements in tabs Why ?
What I am leaving .. Where Am I wrong ?
Please help Me.
Main problem :-
Loop running fast and html() function is not working. When I use alert in loog then loop stay for alert and html() works. Please tell me resoin or solution for this.
Strange because cannot see any asynchronous request anywhere. But usually, you should use the index param of each loop. See if its changing anything:
function makeDirectionTabs() {
jQuery('.adp-warnbox').remove();
jQuery('#adp-placemark').parent().remove();
jQuery('.adp-legal').remove();
jQuery('#fullDirections .adp > div').each(function (i) {
directionContent = jQuery(this).html();
jQuery('#tab' + i).append(directionContent)
});
}
Please see if this helps:
function makeDirectionTabs() {
alert('sdfsf');
jQuery('.adp-warnbox').remove();
jQuery('#adp-placemark').parent().remove();
jQuery('.adp-legal').remove();
var i = 0;
var $divs = jQuery('#fullDirections .adp > div');
for(var i=0; i < $divs.length ; i++){
directionContent = jQuery($divs[i]).html();
jQuery('#tab' + i).append(directionContent)
}
}

JavaScript: How stop a function which is started with $(function(){})

I created a function and then called this function when the page loads, also I need call same the function, but without it existing twice. I want it to just stop from $(function(){}) and call again when an element is clicked on.
function myfunction(){
console.log('message');
}
$(function(){
myFunction();
$('#id').click(function(){
...some code here ...
myFunction();
});
})
When page is loaded the console gives me: "message" - it's ok, but when click on #id then I get this message twice, if again then 3 times;
Here my code
function select_cta(){
$('.cta-id').click(function(){
console.log('-');
$('.cta-id').removeClass('active');
$(this).addClass('active');
var cta_arr = parseInt($(this).attr('id').replace('cta-button-', ''))-1;
$('.cta-image').fadeOut(300).removeClass('active');
$('#'+$(this).attr('id').replace('cta-button', 'cta-image')).fadeIn(300).addClass('active');
if(cta_data[cta_arr]){
$('.cta-actions #cta_id').val(cta_data[cta_arr].id);
}
else{
$('.cta-actions #cta_id').val('');
};
if(cta_data[cta_arr]){
$('.cta-actions #cta_link').val(cta_data[cta_arr].link);
}
else{
$('.cta-actions #cta_link').val('');
};
});
}
$(function(){
select_cta();
$('.add-new-cta').click(function(){
var new_tab = parseInt($(this).prev().attr('id').replace('cta-button-',''))+1;
$(this).before('<div id="cta-button-'+new_tab+'" class="cta-btn cta-id empty" style="display:none;"><span>'+new_tab+'</span><span class="onair">ON</span></div>');
$('#cta-button-'+new_tab).fadeIn(300);
$('.cta-images').append('<div id="cta-image-'+new_tab+'" class="cta-image " style="display:none"><img src="/assets/images/page/placeholder_cta.gif"></div>');
select_cta();
})
});
Your problem that every call to select_cta adds another handler to each of the elements. They all would be executed when the click event fires. Two solutions:
Unbind the event handlers from all elements before you re-add them. To do so, begin the function select_cta with $('.cta-id').off("click").on("click", function(){…
Better: use event delegation:
jQuery(function($){
function getIdNumber($el) {
return parseInt($el.prop('id').replace(/\D/g, ''), 10);
}
var $active = $('.cta-id.active'),
$activeImg = $('.cta-image.active')
$(document).on("click", '.cta-id', function(e) {
$active.removeClass('active');
$active = $(this).addClass('active');
var num = getIdNumber($active);
$activeImg.fadeOut(300).removeClass('active');
$activeImg = $('#cta-image'+num).fadeIn(300).addClass('active');
var cta_arr = num - 1;
if(cta_arr in cta_data) {
$('#cta_id').val(cta_data[cta_arr].id);
$('#cta_link').val(cta_data[cta_arr].link);
} else {
$('#cta_id').val('');
$('#cta_link').val('');
}
});
$('.add-new-cta').click(function(e) {
var $this = $(this),
new_tab = getIdNumber($this.prev())+1,
new_button = $('<div id="cta-button-'+new_tab+'" class="cta-btn cta-id empty" style="display:none;"><span>'+new_tab+'</span><span class="onair">ON</span></div>');
$this.before(new_button);
new_button.fadeIn(300);
$('.cta-images').append('<div id="cta-image-'+new_tab+'" class="cta-image " style="display:none"><img src="/assets/images/page/placeholder_cta.gif"></div>');
})
});

Event doesn't get added in a for-loop

This is the html. If a link is clicked I want to replace the span-element in front of it with some text.
<p><span id="sp1">that1</span> Update1</p>
<p><span id="sp2">that2</span> Update2</p>
<p><span id="sp3">that3</span> Update3</p>
<p><span id="sp4">that4</span> Update4</p>
<p><span id="sp5">that5</span> Update5</p>
As you can see, my idea was to give the spans en the anchors identical id's and a number.
In my jquery-code I loop through all the anchor-elements, give them a click-event that causes the span-element in front of it to be replaced.
<script type="text/javascript" >
$(document).ready(function() {
var numSpans = $("span").length;
for (n=0;n<=numSpans;n++) {
$("a#update" + n).click(function(e){
$('span#sp' + n).replaceWith('this');
e.preventDefault();
});
}
});
</script>
For some reason this does not work.
What am I doing wrong?
The problem with your original code is that you're creating a closure on the variable n. When the event handler is called, it is called with the value of n at the point of invocation, not the point of declaration. You can see this by adding an alert call:
$(document).ready(function() {
var numSpans = $("span").length;
for (n = 1; n <= numSpans; n++) {
$("a#update" + n).click(function(e) {
alert(n); //Alerts '6'
$('span#sp' + n).replaceWith('this');
e.preventDefault();
});
}
})
One way to fix this is to create a closure on the value of n in each iteration, like so:
$(document).ready(function() {
var numSpans = $("span").length;
for (n = 1; n <= numSpans; n++) {
$("a#update" + n).click(
(function(k) {
return function(e) {
alert(k);
$('span#sp' + k).replaceWith('this');
e.preventDefault();
}
})(n)
);
}
})
However, this is messy, and you'd do better to use a more jQuery-y method.
One way to do this would be to remove the ids from your code. Unless you need them for something else, they're not required:
<p><span>that1</span> Update1</p>
<p><span>that2</span> Update2</p>
<p><span>that3</span> Update3</p>
<p><span>that4</span> Update4</p>
<p><span>that5</span> Update5</p>
jQuery:
$(function() {
$('a.update').live('click', function() {
$(this).siblings('span').replaceWith("Updated that!");
});
});
jsFiddle
Don't create functions in a loop. With jQuery, there's no need for an explicit loop at all.
$(function()
{
$('span[id^=sp]').each(function(n)
{
$('#update' + n).click(function(e)
{
$('#sp' + n).replaceWith(this);
return false;
});
});
});
Demo: http://jsfiddle.net/mattball/4TVMa/
You can do way better than that, though:
$(function()
{
$('p > a[id^=update]').live('click', function(e)
{
$(this).prev().replaceWith(this);
return false;
});
});
Demo: http://jsfiddle.net/mattball/xySGW/
Try this:
$(function(){
$("a[id^='update']").click(function(){
var index = this.id.replace(/[^0-9]/g, "");
$("span#sp" + index).replaceWith(this);
e.preventDefault();
});
});

Categories

Resources