Trigger a click event on an inner element - javascript

A row in a table where each first cell contains a link needs to be clicked and open a url.
<table>
<tr>
<td><a class="fancybox" href="detail.aspx?CID=67525">LT5C260A436C41</a></td>
<td>more data</td>
</tr>
<tr>
<td><a class="fancybox" href="detail.aspx?CID=17522">LA5C260D436C41</a></td>
<td>more data</td>
</tr>
...
</table>
The complete row should be clickable instead of only the link top open the detail page in a fancybox, ie in the page itself.
So I tried to do something like this:
$("table tr").bind('click',function(e) {
e.stopPropagation();
$(this).find("a").trigger('click');
});
But it seems that the event is bubbling recursivly resulting in a:
Uncaught RangeError: Maximum call stack size exceeded
How can I trigger the click on the full row instead of only the link in a proper way avoiding the stackoverflow?
UPDATE: I really appreciate the answers below, but my question is about triggering the event, NOT executing the behaviour inside that event. Workarounds could be nice, but not in this case.

This worked well:
$("table tr").click(function(e) {
var $link = $(this).find("a");
if (e.target === $link[0]) return false;
$link.trigger('click');
return false;
});
EDIT:
Why most solutions don't work — they fail, because when the link was clicked, the immediate handler attached runs. The event then bubbles to see if a handler was attached to a table cell, row, etc.
When you suggest triggering a click you cause the recursion: the link was clicked → fancybox → bubbles → aha! table row → trigger the link click → the link was clicked…
When you suggest to stop propagation, please note that event stops bubbling to parent elements, so a click handler attached to body will not be executed.
Why the code above works — we check if the event bubbled from a link. If true, we simply return and stop further propagation.
See the updated fiddle: http://jsfiddle.net/F5aMb/28/

try
$('table tr').click(function() {
var href = $(this).find("a").attr("href");
if(href) {
window.location = href;
}
});

Try this:
$("table tr a").bind('click', function(e) {
e.preventDefault();
window.open($(this).attr('href'));
return false;
});
$("table tr").bind('click', function(e) {
$(this).find("a").trigger('click');
});
I found what went wrong.
In your code,
$("table tr").bind('click',function(e) {
e.stopPropagation();
$(this).find("a").trigger('click');//This line again triggers a click event binded on the tr ELEMENT which contains the 'a' ELEMENT. So it goes into a infinite loop.
});
Update:
This will do.
$("table tr").bind('click', function(e) {
window.location.href = $(this).find("a.fancybox").attr('href');
});
$(this).find("a").trigger('click'); is actually not triggering the default
anchor tag behavior. It just tries to trigger a click event if a click event
is already bound to that element explicitly.

It may be that I misunderstood your question, but doesn't this do what you need:
$("table tr").click(function(e) {
e.stopImmediatePropagation();
if (! $(e.target).is('a')) {
$(this).find("a").trigger('click');
}
});

For the funny purpose of this exercise, here is a pure js solution, i.e., w/o using jQ lib).
Available here for testing: http://jsfiddle.net/Sr5Vy/3/
<table>
<tr id="node_1">
<td><a class="fancybox" href="detail.aspx?CID=67525">LT5C260A436C41</a></td>
<td>more data</td>
</tr>
<tr id="node_2">
<td><a class="fancybox" href="detail.aspx?CID=17522">LA5C260D436C41</a></td>
<td>more data</td>
</tr>
</table>
function AddEvent(id, evt_type, ma_fonction, phase) {
var oElt = document.getElementById(id);
if( oElt.addEventListener ) {
oElt.addEventListener(evt_type, ma_fonction, phase);
} else if( oElt.attachEvent ) {
oElt.attachEvent('on'+evt_type, ma_fonction);
}
// Debug
// alert('a \'' + evt_type + '\' event has been attached on ' + id );
return false;
}
function getElementsByRegExpOnId(search_reg, search_element, search_tagName) {
search_element = (search_element === undefined) ? document : search_element;
search_tagName= (search_tagName === undefined) ? '*' : search_tagName;
var id_return = new Array;
for(var i = 0, i_length = search_element.getElementsByTagName(search_tagName).length; i < i_length; i++) {
if (search_element.getElementsByTagName(search_tagName).item(i).id &&
search_element.getElementsByTagName(search_tagName).item(i).id.match(search_reg)) {
id_return.push(search_element.getElementsByTagName(search_tagName).item(i).id) ;
}
}
return id_return; // array
}
function FollowSpecialLinks(event) {
// Debug
// alert('event was successfully attached');
// Prevent propagation
event.preventDefault();
// Identify targetted node (eg one of the children of <tr>)
var targetted_elt = ShowEventSource(event);
//alert('Event\'s target : ' + targetted_elt);
// Extract the targetted url
if (targetted_elt == "A") {
var current_link = GetEventSource(event).href;
} else {
var current_tr = GetEventSource(event).parentNode;
var child_links = current_tr.getElementsByTagName('a');
var current_link = child_links[0].href;
}
// Now open the link
if(current_link) {
// Debug
alert('will now open href : ' + current_link);
window.location = current_link;
}
}
function GetEventSource(event) {
var e = event || window.event;
var myelt = e.target || e.srcElement;
return myelt;
}
function ShowEventSource(event) {
var elmt;
var event = event || window.event; // W3C ou MS
var la_cible = event.target || event.srcElement;
if (la_cible.nodeType == 3) // Vs bug Safari
elmt = la_cible.parentNode;
else
elmt = la_cible.tagName;
return elmt;
}
// Get all document <tr> id's and attach the "click" events to them
my_rows = new Array();
my_rows = getElementsByRegExpOnId(/^node_.+/, document , 'tr') ;
if (my_rows) {
for (i=0; i< my_rows.length; i++ ) {
var every_row = document.getElementById( my_rows[i] ) ;
AddEvent(every_row.id, 'click', FollowSpecialLinks, false);
}
}

Try
$(".fancybox").parent('td').parent('tr').bind('click',function(e) {
e.stopPropagation();
$(this).find("a").trigger('click');
});

Have you tried stopping immediate propagation when you click the link?This way you should stop the recursion
$('a').click(function(e){
e.stopImmediatePropagation();
alert('hi');
});
fiddle here: http://jsfiddle.net/3VMGn/2/

In order to compensate for the bubbling, you need to detect the target of the event and not click on the link more than once.
Also, jQuery's "trigger" function won't work for plain links, so you need a specialized click function.
you can try it out at: http://jsfiddle.net/F5aMb/27/
$("table tr").each(function(i, tr){
$(tr).bind('click',function(e) {
var target = $(e.target);
if( !target.is("a") ) {
clickLink($(this).find("a")[0]);
}
})
});
function clickLink(element) {
if (document.createEvent) {
// dispatch for firefox + others
var evt = document.createEvent("MouseEvents");
evt.initEvent("click", true, true ); // event type,bubbling,cancelable
return !element.dispatchEvent(evt);
} else {
//IE
element.click()
}
}

I was able to do it by giving each link a unique ID and then using jQuery to set the click event of that unique ID to redirect the window to the appropriate page.
Here is my working example: http://jsfiddle.net/MarkKramer/F5aMb/2/
And here is the code:
$('#link1').click(function(){
// do whatever I want here, then redirect
window.location.href = "detail.aspx?CID=67525";
});
$('#link2').click(function(){
// do whatever I want here, then redirect
window.location.href = "detail.aspx?CID=17522";
});
$("table tr").click(function(e) {
e.stopImmediatePropagation();
$(this).find("a").trigger('click');
});

You can do what you want with following code. I tested it on you jsfilddle seems working.
$("table tr").click(function(e) {
// check if click event is on link or not.
// if it's link, don't stop further propagation
// so, link href will be followed.
if($(e.target).attr('class')=='fancybox'){
alert('you clicked link, so what next ?.');
// else if click is happened somewhere else than link,
// stop the propagation, so that it won't go in recursion.
}else{
alert('no link clicked, :( ');
alert('now clicking link prgrammatically');
$(this).find('a').click();
e.preventDefault();
}
});
Let me know, if you want to achieve something else than this.

I think .click() or .trigger("click") only fires the event handlers for onclick.
See a sample here http://jsfiddle.net/sethi/bEDPp/4/
. Manually clicking on the link shows 2 alerts while firing the event through jQuery shows only 1 alert.
You can also refer to this link : re-firing a click event on a link with jQuery
Solution
If you are just looking to open a fancybox try this:
$("table tr").bind('click',function(e) {
var elem = $(e.target);
if(elem.is('a')){
return;
}
e.stopImmediatePropagation();
var parent= elem.is('tr') ? elem:elem.parents("tr").eq(0);
parent.find("a").trigger('click.fb');
});
where click.fb is the event that fancybox binds with the anchor element.

$('a.fancybox').click(function(evt){evt.stopPropagation())});
$('table tr:has[.fancybox]').click(function(evt){
$(this).find('.fancybox').trigger('click')
})

I think I have what you're looking for. What you need to do is to call click() on the anchor tag in the handler, and make sure you ignore events from the anchor itself. Also, WebKit doesn't support click(), so you have to implement it yourself.
Notice from the fiddle below that it properly follows the link target, that is, opens a new window, or loads into the same window. http://jsfiddle.net/mendesjuan/5pv5A/3/
// Some browsers (WebKit) don't support the click method on links
if (!HTMLAnchorElement.prototype.click) {
HTMLAnchorElement.prototype.click = function() {
var target = this.getAttribute('target');
var href = this.getAttribute('href');
if (!target) {
window.location = href;
} else {
window.open(href, target);
}
}
}
$("table tr").bind('click',function(e) {
// This prevents the stack overflow
if (e.target.tagName == 'A') {
return;
}
// This triggers the default behavior of the anchor
// unlike calling jQuery trigger('click')
$(this).find("a").get(0).click();
});

My usecase was to trigger a click when a -element was clicked. Checking the type of the target element solves the recursive call problem.
$('#table tbody td').click(function(e){
if ($(e.target).is('td')) {
$(this).find('input').trigger('click');
}
});

Related

How do I onmouseover in a <tr> check to see if a key was pressed

I have a large table with a lot of data. Basically I'm trying to check, if a letter was pressed while someone was hovering over a <tr>. What I'm trying to do is basically blackout on the whole screen except for the hovered row when someone presses the letter f so that it can basically just focus on that row. Easier to see in the midst of a lot of data.
Here's what I have so far. Don't know if I'm in the right direction, but it's not detecting me pressing the letter. Also, if they press f again or esc or click outside of the row, I'd like it to go back to normal.
$(function(){
$('#report tr').on('mouseover',function(){
$('#report tr').removeClass('sel');
$(this).addClass('sel');
$(this).keypress(function(event){
if(event==70){
alert('hello');
}
});
});
});
From your example, as to why $('#report tr') does not receive the keypress event:
A keypress event handler can be attached to any element, but the event is only sent to the element that has the focus.
(https://api.jquery.com/keypress/)
However you cannot simply give focus to $('#report tr') with $('#report tr').focus():
The focus event is sent to an element when it gains focus. This event is implicitly applicable to a limited set of elements, such as form elements (, , etc.) and links (). In recent browser versions, the event can be extended to include all element types by explicitly setting the element's tabindex property.
(https://api.jquery.com/focus/)
If you wish to give $('#report tr') focus you will need to set a tabindex on your $('#report tr') elements.
An example of how this may be implemented:
<html>
<head>
<title>Pass keypress event to TR</title>
</head>
<body>
<table>
<tr tabindex="1">
<td>data 1</td>
<td>data 2</td>
</tr>
<tr tabindex="2">
<td>data 3</td>
<td>data 4</td>
</tr>
</table>
<script type="application/javascript" src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script type="application/javascript">
$(function() {
$rows = $('table tr');
$rows.keypress(function(e) {
if (e.which == 102) {
$(this).css('background-color', '#ff0000');
}
});
$rows.on('mouseover', function(e) {
$(this).focus();
});
});
</script>
</body>
</html>
I would do something like this:
$(function () {
$('#report tr').hover(
function () {
$(this).addClass('sel');
},function(){
$(this).removeClass('sel')
});
$(document).keypress(function (e) {
if (e.keyCode == 102) //if they pressed f
//do something with the selected item
});
});
Basically, just attaching the keypress event to the document instead of trying to attach it to a specific element inside your hover function.
Edit: Here's another possibility based on your comment. Note that you would need to add a way to remove the sel class as well:
$(function () {
var currentElement;
$('#report tr').hover(
function () {
currentElement = $(this);
});
$(document).keypress(function (e) {
if (e.keyCode == 102) //if they pressed f
currentElement.addClass('sel');
});
});
Here's a snippet doing pretty much what you want:
$(document).ready(function () {
var currentRow = null, // Stores the currently hovered TR
fKey = false, // Indicates, if F has been pressed
table = $('#table'), // Holder for the table
stopBlackout = function () { // Removes "blackout"
$('body').removeClass('blackout');
if (currentRow) {
currentRow.removeClass('hilite');
}
},
// Starts "blackout"
startBlackout = function (row) { // row = row element
row.addClass('hilite');
$('body').addClass('blackout');
if (currentRow[0] !== row[0]) { // Remove hilite if different row only
currentRow.removeClass('hilite');
}
currentRow = row;
},
// Keydown listener toggles "blackout"
toggleBlackout = function (e) { // e = event object
if ('form' in e.target) {return;} // Exit if a form element is active
if (e.which === 27 || e.which === 70) { // Action when hit Esc or F only
fKey = !fKey;
if (e.which === 27) {
fKey = false;
}
if (!fKey) {
stopBlackout();
} else if (currentRow) { // Start "blackout" when having a hovered row
startBlackout(currentRow);
}
}
};
table.mouseenter(function () { // Activate table to receive key presses
this.focus();
});
table.mouseleave(function () { // End "blackout" and stop receiving keypresses
stopBlackout();
table.blur();
});
table.keydown(toggleBlackout);
table.mouseover(function (e) { // Highlight active row according to mouse hover
var row = $(e.target);
if (row[0].tagName !== 'TR') { // Usually TD or other element triggers mouseover
row = row.closest('tr'); // Set target to TR
if (!row.length) {return;} // Exit if e.target was TBODY or TABLE
if (fKey) {
startBlackout(row);
}
currentRow = row; // Update the currently hovered row holder
}
});
});
.blackout {
background: #000000;
}
.hilite {
background: #ffffff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table id="table" tabindex="-1">
<tr><td>R1<b>C</b>1</td><td>R1C2</td></tr>
<tr><td>R1C2</td><td>R2C2</td></tr>
<tr><td>R1C3</td><td>R3C2</td></tr>
<tr><td>R1C4</td><td>R4C2</td></tr>
</table>
Some explanations
All events have been attached to the table element, not to it's children. This reduces event listeners on the page and makes it faster, especially if the table is very large. The table must exist before adding these listeners, but you can add content afterwards.
keydown is used, since Esc doesn't fire keypress in all browsers. fKey variable in the code indicates, whether "blackout" is on or off.
The activate key (F) works only when hovering over the table, but not when any form element is active.
mouseover is fired every time the mouse is moved from an element to another within a tr, hence its handler has some extra checkings.
mouseenter handler makes the table to receive key presses automatically when hovered over it, no need to click to activate table first.
mouseleave handler stops table to receive key presses, and removes the "blackout".
tabindex of the table is set to -1 to make the table to be able to receive focus, but putting it out of tabbing order.

Trigger click event on DOM element

I tried to trigger a click event on an selected DOM element but my code won't work.
You can see my attempt on JSFiddle.
<ul class="list-group">
LG GOLA 8M
LG 5-6M
LP 5-6M
</ul>
$(document).ready(function() {
// I get the string tr from URL parameters
var tr = "fix_LG%20GOLA%208M";
if (tr !== null) {
var terminrahmen = $('.list-group-item').filter(function() {
return $(this).text() === decodeURI(tr).substring(4);
});
// Trigger click event on .list-group-item
terminrahmen.click();
}
// The function to be executed
$('.list-group-item').click(function() {
alert($(this).text());
});
});
When the DOM was loaded I collect some data from URL parameters and compare the data with DOM elements. This part works fine.
After that I get an element and I would like to trigger an click event. The click event should "execute" a specified function.
Have anyone a good solution for me? Thanks in advance.
http://jsfiddle.net/azg2R/2/
Put the click event on top in the ready event.. The click event needs to be triggered after registering the event. It was not happening before
$(document).ready(function() {
// The function to be executed
$('.list-group-item').click(function() {
alert($(this).text());
});
// I get the string tr from URL parameters
var tr = "fix_LG%20GOLA%208M";
if (tr !== null) {
var terminrahmen = $('.list-group-item').filter(function() {
return $(this).text() === decodeURI(tr).substring(4);
});
// Trigger click event on .list-group-item
terminrahmen.click();
}
});
The problem is that you are triggering click event before attaching event handler to it. So you just need to move click handler before triggering click and everything would work as you expected:
$(document).ready(function() {
// The function to be executed
$('.list-group-item').click(function() {
alert($(this).text());
});
// I get the string tr from URL parameters
var tr = "fix_LG%20GOLA%208M";
if (tr !== null) {
var terminrahmen = $('.list-group-item').filter(function() {
return $(this).text() === decodeURI(tr).substring(4);
});
// Trigger click event on .list-group-item
terminrahmen.click();
}
});
JSFiddle

Gracefully bubble up with a clicktarget

I am working with this plugin that runs off of the data attribute. Basically when you click anywhere on the body it will determine if the click target has this specific data-vzpop. The problem is lets say I have a div and inside the div is an a href. It only acknowledges the a href as the click target and not the div (which makes sense).
What I want to try and do in some cases is put the data attribute on the containing div that way anything within the div works on click.
Here is a sample of the issue with jsfiddle it requires viewing the console so you can actually see which element is registered as being clicked.
<div data-vzpop>
Click Me
</div>
$('body').on('click', function(evt){
var clickTarget = evt.target;
if ($(clickTarget).attr('data-vzpop') !== undefined){
evt.preventDefault();
console.log('called correctly')
} else {
console.log('not called correctly')
}
console.log(clickTarget)
});
fiddle
You would use Event delegation:
$('body').on('click', '[data-vzpop]', function(evt) {
This will only trigger when the evt.target has a data attribute of data-vzpop, no matter the value.
If you want items inside the [data-vzpop] to trigger it as well, you would use your original click event but check that the $(clickTarget).closest('[data-vzpop]').length > 0 to determine if it's a nested target.
$('body').on('click', function(evt){
var clickTarget = evt.target;
if ($(clickTarget).attr('data-vzpop') != null ||
$(clickTarget).closest('[data-vzpop]').length > 0){
evt.preventDefault();
console.log('called correctly')
} else {
console.log('not called correctly')
}
console.log(clickTarget)
});

html div onclick event

I have one html div on my jsp page, on that i have put one anchor tag, please find code below for that,
<div class="expandable-panel-heading">
<h2>
<a id="ancherComplaint" href="#addComplaint"
onclick="markActiveLink(this);">ABC</a>
</h2>
</div>
js code
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
alert('123');
});
function markActiveLink(el) {
alert($(el).attr("id"));
}
here I when I click on div I got alert with 123 message, its fine but when I click on ABC I want message I want to call markActiveLink method.
JSFiddle
what is wrong with my code? please help me out.
The problem was that clicking the anchor still triggered a click in your <div>. That's called "event bubbling".
In fact, there are multiple solutions:
Checking in the DIV click event handler whether the actual target element was the anchor
→ jsFiddle
$('.expandable-panel-heading').click(function (evt) {
if (evt.target.tagName != "A") {
alert('123');
}
// Also possible if conditions:
// - evt.target.id != "ancherComplaint"
// - !$(evt.target).is("#ancherComplaint")
});
$("#ancherComplaint").click(function () {
alert($(this).attr("id"));
});
Stopping the event propagation from the anchor click listener
→ jsFiddle
$("#ancherComplaint").click(function (evt) {
evt.stopPropagation();
alert($(this).attr("id"));
});
As you may have noticed, I have removed the following selector part from my examples:
:not(#ancherComplaint)
This was unnecessary because there is no element with the class .expandable-panel-heading which also have #ancherComplaint as its ID.
I assume that you wanted to suppress the event for the anchor. That cannot work in that manner because both selectors (yours and mine) select the exact same DIV. The selector has no influence on the listener when it is called; it only sets the list of elements to which the listeners should be registered. Since this list is the same in both versions, there exists no difference.
Try this
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
alert('123');
});
$('#ancherComplaint').click(function (event) {
alert($(this).attr("id"));
event.stopPropagation()
})
DEMO
Try following :
$('.expandable-panel-heading').click(function (e) {
if(e.target.nodeName == 'A'){
markActiveLink(e.target)
return;
}else{
alert('123');
}
});
function markActiveLink(el) {
alert($(el).attr("id"));
}
Here is the working demo : http://jsfiddle.net/JVrNc/4/
Change your jQuery code with this. It will alert the id of the a.
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
markActiveLink();
alert('123');
});
function markActiveLink(el) {
var el = $('a').attr("id")
alert(el);
}
Demo
You need to read up on event bubbling and for sure remove inline event handling if you have jQuery anyway
Test the click on the div and examine the target
Live Demo
$(".expandable-panel-heading").on("click",function (e) {
if (e.target.id =="ancherComplaint") { // or test the tag
e.preventDefault(); // or e.stopPropagation()
markActiveLink(e.target);
}
else alert('123');
});
function markActiveLink(el) {
alert(el.id);
}
I would have used stopPropagation like this:
$('.expandable-panel-heading:not(#ancherComplaint)').click(function () {
alert('123');
});
$('#ancherComplaint').on('click',function(e){
e.stopPropagation();
alert('hiiiiiiiiii');
});
Try out this example, the onclick is still called from your HTML, and event bubbling is stopped.
<div class="expandable-panel-heading">
<h2>
<a id="ancherComplaint" href="#addComplaint" onclick="markActiveLink(this);event.stopPropagation();">ABC</a>
</h2>
</div>
http://jsfiddle.net/NXML7/1/
put your jquery function inside ready function for call click event:
$(document).ready(function() {
$("#ancherComplaint").click(function () {
alert($(this).attr("id"));
});
});
when click on div alert key
$(document).delegate(".searchbtn", "click", function() {
var key=$.trim($('#txtkey').val());
alert(key);
});

X-Editable: stop propagation on "click to edit"

I have an editable element inside a div which itself is clickable. Whenever I click the x-editable anchor element, the click bubbles up the DOM and triggers a click on the parent div. How can I prevent that? I know it's possible to stop this with jQuery's stopPropagation() but where would I call this method?
Here's the JSFiddle with the problem: http://jsfiddle.net/4RZvV/ . To replicate click on the editable values and you'll see that the containing div will catch a click event. This also happens when I click anywhere on the x-editable popup and I'd like to prevent that as well.
EDIT after lightswitch05 answer
I have multiple dynamic DIVs which should be selectable so I couldn't use a global variable. I added an attribute to the .editable-click anchors which get's changed instead.
editable-active is used to know if the popup is open or not
editable-activateable is used instead to know if that .editable-click anchor should be treated like it is
$(document).on('shown', "a.editable-click[editable-activateable]", function(e, reason) {
return $(this).attr("editable-active", true);
});
$(document).on('hidden', "a.editable-click[editable-activateable]", function(e, reason) {
return $(this).removeAttr("editable-active");
});
The check is pretty much like you've described it
$(document).on("click", ".version", function() {
$this = $(this)
// Check that the xeditable popup is not open
if($this.find("a[editable-active]").length === 0) { // means that editable popup is not open so we can do the stuff
// ... do stuff ...
}
})
For the click on the links, simply catch the click event and stop it:
$("a.editable-click").click(function(e){
e.stopPropagation();
});
The clicks within X-editable are a bit trickier. One way is to save a flag on weather the X-editable window is open or not, and only take action if X-editable is closed
var editableActive = false;
$("a.editable-click").on('shown', function(e, reason) {
editableActive = true;
});
$("a.editable-click").on('hidden', function(e, reason) {
editableActive = false;
});
$("div.version").click(function(e) {
var $this;
$this = $(this);
if(editableActive === false){
if ($this.hasClass("selected")) {
$(this).removeClass("selected");
} else {
$(this).addClass("selected");
}
}
});
Fixed Fiddle
It's not pretty, but we solved this problem with something like:
$('.some-class').click(function(event) {
if(event.target.tagName === "A" || event.target.tagName === "INPUT" || event.target.tagName === "BUTTON"){
return;
}
We're still looking for a solution that doesn't require a specific list of tagNames that are okay to click on.

Categories

Resources