Javascript classes and jQuery event listeners - javascript

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"); });
});
}

Related

Is it a scope issue?

I add a close button to the card. I try this code but the close button seems not working.
$('#add-pet').on('click', e => {
// Grab info from the form
let $name = $('#pet-name').val();
let $species = $('#pet-species').val();
let $notes = $('#pet-notes').val();
let $newPet = $(
'<section class="six columns"><div class="card"><p><strong>Name:</strong> ' + $name +
'</p><p><strong>Species:</strong> ' + $species +
'</p><p><strong>Notes:</strong> ' + $notes +
'</p><span class="close">×</span></div></section>'
);
// Attach the new element to the page
$('#posted-pets').append($newPet);
});
$('.close').on('click', function() {
$(this).parent().remove();
});
However, when I move this code:
$('.close').on('click', function() {
$(this).parent().remove();
});
right after the $('#posted-pets').append($newPet);
Then it works OK.
Why it is like that?
Whenever you want to make an event for an element which may be appended via jquery, you can try:
$(document).on('click', '.close', function() {
$(this).parent().remove();
});
It works after you appending span.close tag. Even if outside the scope
$('#add-pet').on('click', /*...*/);
Update:
You can also try:
$('#add-pet').on('click', e => {
let close_tag = $('<span>').addClass('close');
// do stuff...
// set event
close_tag.on('click', function () {
$(this).parent().remove();
});
$('#posted-pets').append(close_tag);
});
When the close function is outside of the div, it's trying to attach to existing .close elements and the element you are trying to attach to doesn't exist at that point in time. You need to do it inside because you need to have the $newPet element actually created before you can attach to it.
$('.close') will search in the dom.
If you haven't appended your html, then it can't be found by jQuery

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');
}
);

get clicked link-button ID where all buttons already bind to one function

the app receive a n html dive and create a page and append it to the app
I bind all link-buttons in set of pages to one function
which will do different tasks depends on the id of the page
now I have a problem when a page has more than one link-button
I need the ID of the clicked button
Html:
<a id="x">x </a>
<a id="y">y </a>
Js:
var btns = [];
$('#page-' + newpages[j].pageID + ' a').each(function () {
btns.push({
id: this.id,
value: this.value,
name: this.name
});
});
for (i in btns) {
$('#' + btns[i].id).bind('click', function () {
test(btns[i].id)
});
// bin all buttons in current page to test()
}
};
};
function test(x) {
var page = $('.ui-page-active').attr('id');
/////////
//here I'm trying to ge the ID of clicked button of that page (each ID means something)
var pos = '';
$('#' + page + ' a').click(function () {
//Get the id of this clicked item
var BID = $(this).attr("id");
alert(BID);
send(BID);
});
Why don't you just bind to the click event on each button independently? If you switch by ID anyway why go through a generic function, any shared functionality can be abstracted into a function and utilized by each click handler so you loose nothing.

How can I get to know which anchor tag got clicked?

I am creating my content dynamically, When a anchor tag is clicked navigate() function is called. How can i determine which anchor tag was clicked?
function navigate()
{
//var location=$(this).attr("id");
switch(location)
{
/*case "Configuration": $('#detailTable').empty();
$('#detailTable').append(navigateConfig);
break;*/
default: alert(location+" a tag was clicked");
}
}
$('#detailTable').empty();
$('<div width="100%">')
.attr('id','javainfoSpan')
.html('<div class="titleBlue">Configuration>'+productname+'>Java Properties</div>'+
//some other stuff
'</div>')
.appendTo('#detailTable');
Update:
My question is simple
there will be a number of a elements inside detailTable.
how can I get to know in some js function, which a element was clicked?
I see what you're doing now, you're creating the a elements on the fly. If you call javascript:navigate() then you're using standard javascript, and not jquery (jquery is required to use the $(this) selector).
Instead you should have this:
$("body").on('click', 'a', function() {
var location = $(this).attr('id');
switch(location){ /* ... */ }
});
This will catch the click event in jquery for any a element that you either create on the fly or that's already there when the page loads.
Remember, if you're using id then you need to set the id attr on the a element.
Here is a way to handle this too:
$(document).ready(function() {
var productname = "mytest";
$('#detailTable').empty();
$('<div width="100%">').attr('id', 'javainfoSpan').html('<div class="titleBlue">Configuration>' + productname + '>Java Properties</div>' + '<table id="list1" width="100%"></table>' + '<div id="gridpager"></div>' + '</div>').appendTo('#detailTable');
$(".navigate").click(function() {
var location = $(this).attr("id");
switch (location) {
case "Configuration":
$('#detailTable').empty();
$('#detailTable').append(navigateConfig);
break;
case "mytest":
alert("My test was clicked");
break;
default:
alert(location + " a tag was clicked");
}
});
});
See it live on jsfiddle
Try this:
function navigate($element) {
//var location = $element.attr("id");
switch (location) {
/*case "Configuration": $('#detailTable').empty();
$('#detailTable').append(navigateConfig);
break;*/
default: alert(location+" a tag was clicked");
}
}
$('#detailTable').empty();
$('<div width="100%">')
.attr('id','javainfoSpan')
.html('<div class="titleBlue">Configuration>'+productname+'>Java Properties</div>'+
//some other stuff
'</div>')
.appendTo('#detailTable');
// Pre jQuery 1.7...
$(".titleBlue").delegate("A", "click", function() {
navigate($(this));
}
// jQuery 1.7...
$(".titleBlue A").on("click", function() {
navigate($(this));
}
I changed the handler to use the delegate() method of jQuery (or the on() method for jQ 1.7+). Using this it makes it easier to pass the element which caused the event to your processing function, which it does as the $element variable.
You can then do with this as you need.
you have to iterate through each element of using jquery "each" function. By "this" you can get the click object.

Javascript variable scope issue with jquery click event

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/

Categories

Resources