Javascript variable scope issue with jquery click event - javascript

I am trying to assign a series of objects stored in an array to jquery click event handlers.
The problem is , when the event fires, I only ever references the last object in the array.
I have put together a simple example to show the problem:
function dothis() {
this.btns = new Array('#button1', '#button2');
}
// Add click handler to each button in array:
dothis.prototype.ClickEvents = function () {
//get each item in array:
for (var i in this.btns) {
var btn = this.btns[i];
console.debug('Adding click handler to button: ' + btn);
$(btn).click(function () {
alert('You clicked : ' + btn);
return false;
});
}
}
var doit = new dothis();
doit.ClickEvents();
The HTML form contains a couple of buttons:
<input type="submit" name="button1" value="Button1" id="button1" />
<input type="submit" name="button2" value="Button2" id="button2" />
When button1 is clicked, it says "You clicked #Button2"
It seems that both button click handlers are pointing to the same object inside var btn.
Considering the variable is inside the for loop, I cannot understand why.
Any ideas?

You need a function factory to close the loop variable, such as this:
//get each item in array:
for (var i=0; i<this.btns.length; i++) {
$(this.btns[i]).click(function(item) {
return function () {
alert('You clicked : ' + item);
return false;
}
}(this.btns[i]));
}
Another good option is to let jquery help you. Use jQuery.each(). The variable btn here is local to the handler function, and so isn't reused between iterations. This allows you to close it and have it keep its value.
$.each(this.btns, function() {
var btn = this;
$(this).click(function () {
alert('You clicked : ' + btn);
return false;
}
});

within an event handler, 'this' usually refers to the element firing the event, in this case, it would be your button
so the solution to your problem is fairly easy, instead of referencing the btn variable, which lives in a higher scope and gets mutated long before the event handler fires, we simply reference the element that fired the event and grab its ID
$(btn).click(function () {
alert('You clicked : #' + this.id);
return false;
});
Note: if your array contains other selectors that just the ID, this will obviously not reflect that and simply continue to show the ID
Lucky, the click handler (and all other event handlers afaik) take an extra parameter for eventData, useful like so:
$(btn).click(btn, function (event) {
alert('You clicked : #' + event.data);
return false;
});
User an array if you're passing multiple things:
$(btn).click(['foo', 'bar'], function (event) {
alert('this should be "foo": ' + event.data[0]);
alert('this should be "bar": ' + event.data[1]);
return false;
});

you have to use closures for this.
i'm not sure if i remember the correct syntax but you could try this:
$(btn).click(function () {
return function() {
alert('You clicked : ' + btn);
return false;
}
});

maybe you need to change just the click binding:
$(btn).click(function () {
alert('You clicked : ' + $(this).attr('id'));
return false;
});

Your problem is here:
alert('You clicked : ' + btn);
btn retains the value from the last time it was called in the loop. Read the value from the button in the event.
$(btn).data('selector', btn).click(function () {
alert('You clicked : ' + $(this).data('selector'));
return false;
});
http://jsfiddle.net/Mc9Jr/1/

Related

How can we get val from keyup in jquery

i want give val from keyup in jquery
my code is :
var vartest;
$( ".target" ).keyup(function() {
vartest= this.value;
console.log('in func:' + vartest);
});
console.log('out of func:' + vartest);
but vartest is undefined
Your function triggers only once your Element receives an event.
At the time you were calling vartest (outside of your function) its value is still undefined because the event (that actually attaches a value) will trigger at a later time.
Create a function getTargetsValues and call that function when needed.
Instead of "keyup" you might eventually listen for the "input" event:
// Cache your elements
const $targets = $(".target");
// Use this function to get an Array of inputs .target values
function getTargetsValues () {
return $targets.get().map(el => el.value);
}
$targets.on("input", function() {
console.log('in func: ' + getTargetsValues());
});
console.log('out of func: ' + getTargetsValues());
<input class="target" type="text" value="1. target">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
I’m not sure if this is what you need, but if you want to get value of input where event happened, you should take it from event target:
$(‘.target’).keyup(e => {
vartest = e.target.value;
});

Dynamically created buttons won't fire when clicked

I'm creating buttons based on what a user enters into an input box. However, the function i have linked to the dynamically created buttons won't fire when pressed.
function btnCreate() {
num++;
userBtn = $("<button>")
userBtn
.addClass("btn search-term-btn dynamicElement")
.appendTo($(".btn-holder"))
.text(topics)
.attr("data-name", topics);
usedTopics.push(topics + num);
topics = [];
console.log(num);
};
$(".search-term-btn").on("click", ".dynamicElement", function () {
// takes the name of the button
searchValue = $(".search-term").attr("data-name");
console.log(searchValue);
})
The class is correct, ive checked with the inspector. I just can't seem to figure out why it's unresponsive
Create the click event on DOM.
$(document).on("click", ".search-term-btn .dynamicElement", function () {
console.log(this)
});
while you are creating the buttons, you can add the onclick function there..
like userBtn = $("<button onlcikc="somefunction(this)">")
OR
you can use on function which is
$('body').on( "click",".dynamicElement", function() {
//your code
});

How to pass a HTML control to another javascript function

I want to pass HTML control to another function inside JavaScript. I am calling a modal popup which has a input control and a save button.
The function in which i am calling the modal popup has entire GridView row as a parameter. I want to pass this to another javascript function which will be called on the button click inside of modal dialog.
I tried as below but it passes a string variable.
function ShowDialogPeoplePicker(id, requestType, cntrl) {
var row = cntrl.parentNode.parentNode;
var rowIndex = row.rowIndex - 1;
var Approvers = row.cells[1].getElementsByTagName("span")[0];
if (requestType == "AddApprovers") {
$('#btnAddApprover').removeAttr('onclick');
$('#btnAddApprover').attr('onClick', 'if (!setApprovers(\'' +cntrl + '\')) return false;');
}
}
The below function will be called on a button click and will set the values inside GridView row.
function setApprovers(cntrl)
{
var usernames= $("#hdnApproversName_CTO").val();
var row = cntrl.parentNode.parentNode;
var rowIndex = row.rowIndex - 1;
row.cells[1].getElementsByTagName("span")[0].innerHTML = usernames;
$("#overlayTasks").hide();
$("#dialogTasks").hide();
return false;
}
Instead of attaching your click handler like this:
$('#btnAddApprover').attr('onClick', 'if (!setApprovers(\'' +cntrl + '\')) return false;');
Try this instead:
$('#btnAddApprover').on('click', function() {
setApprovers(cntrl);
});
If you need to remove previously added event listeners, you can do that with:
$('#btnAddApprover').off('click');
Or if you want to attach the listener to listen just one time in the first place, you can use:
$('#btnAddApprover').one('click', function() {
setApprovers(cntrl);
});
(with one instead of on). Hope this helps!
Instead of
$('#btnAddApprover').attr('onClick', 'if (!setApprovers(\'' +cntrl + '\')) return false;');
use
$('#btnAddApprover').click(function() {
return setApprovers(cntrl);
}

Why is click event handler for a submit button in a colorbox defined in a jQuery prototype method not invoked

I have added a function to jQuery prototype as below. What I want to do is when this method is invoked, generate an html form based on the arguments passed to the method and show it in a colorbox.
(function($) {
$.fn.myFunction = function(data){
var form = $('<form name="people"></form>');
var index;
for (index = 0; index < data.length; index++) {
var match = data[index];
$('<input type="radio" name="person">' + match['name'] + ' [' + match['uri'] + ']<br> ')
.attr("value", match['uri'])
.appendTo(form);
}
$('<input type="button" id="a_button" value="Add"/><br>')
.appendTo(form);
var list = $('<div>').append(form).html();
$('#a_button').click(
function(){
console.log('message from event handler');
}
);
$.colorbox({ innerWidth:420, innerHeight:315, html: list });
};
})(jQuery);
As you can see, form has a button called Add using which I hope to make an ajax request. But unfortunately click event handler attached to this button doesn't seem to be invoked.
Does anyone have any idea about what's wrong here? myFunction is actually invoked by a drupal ajax command in case if that's helpful.
You are appending the form to the DOM after attaching the event handler.
$('#a_button') searches the DOM at that specific point in time, but the form is not added to the DOM until after your call to colorbox with list as a parameter.
Try a permanent delegated event handler instead (or simply add the click handler after the colorbox line).
e.g.
$(document).on("click", "#a_button", function(){
console.log('message from event handler');
});
or
$.colorbox({ innerWidth:420, innerHeight:315, html: list });
$('#a_button').click(
function(){
console.log('message from event handler');
}
);

Javascript classes and jQuery event listeners

I'm writing a class that needs to attach event listeners to objects within a respective sections (#one and #two in this example), but I'm having issues passing variables from the class to set up the jQuery event listeners.
<script type="text/javascript">
function myClass(id) {
this.id = id;
$(document).ready(function(){
$(this.id + ' .filter').click(function(){ alert("You clicked a filter"); });
});
}
one = new myClass('#one');
two = new myClass('#two');
</script>
<div id="one">
I am link one
</div>
<div id="two">
I am link two
</div>
... unfortunately variable scope doesn't agree with me; this.id cannot be accessed from within $(document).ready(), and so the event listeners don't fire. How can I access it?
This is because "this" is a keyword which references the object on which the current function was invoked. With jQuery event handlers, this object is the DOM element on which the event hander was registered (i.e. document in this case.) Use a different variable name to store your object:
<script type="text/javascript">
function myClass(id) {
var me = this;
this.id = id;
$(document).ready(function(){
$(me.id + ' .filter').click(function(){ alert("You clicked a filter"); });
});
}
one = new myClass('#one');
two = new myClass('#two');
</script>
You need to make a local copy of this to use it inside inner functions:
function myClass(id) {
this.id = id;
var that = this;
$(document).ready(function(){
$(that.id + ' .filter').click(function(){ alert("You clicked a filter"); });
});
}
In this case, you don't need to declare it in another variable at all, just swap out id for this.id in your document.ready function:
function myClass(id) {
$(document).ready(function(){
$(id + ' .filter').click(function(){ alert("You clicked a filter"); });
});
}
However, if you did some processing to it, you could always alias this in another variable:
function myClass(id) {
var base = this;
base.id = id;
// Other items set on base.value
$(document).ready(function(){
$(base.id + ' .filter').click(function(){ alert("You clicked a filter"); });
});
}

Categories

Resources