I want to make it so that when a track completes playing it automatically calls a javascript function which clicks the next track button so that the playlist continues to play. So far i have:
function next() {
$("#nextTrack").click();
}
But that doesn't seem to do anything when it is called, anyone know where i am going wrong?
The way to trigger the click event on the DOM element itself is with:
$("#nextTrack")[0].click();
This gets the first (only) DOM element matched (removes it from the jQuery wrapper) and calls the native click method.
The only reasoning I can provide for this is because trigger doesn't (or hasn't, in past versions) attempted to call the native method. I swear in the most recent version, I can use .trigger("click") (same as .click()) and it will effectively click the element...executing native any click handlers and jQuery handlers as well.
trigger is tricky because jQuery stores any event handlers bound with jQuery.on, jQuery.bind, etc. in a special place. When the native event is fired, or .trigger("event_name") is used, all those special handlers are executed. But for some reason, the native event isn't always triggered (as you seem to have found out). I'm not sure if it's because of the version of jQuery or the event type.
UPDATE:
The reason this is happening is because jQuery treats <a> specially when using .trigger("event_name"), specifically for the click event.
After blabbering with the stuff above, I decided to look into the jQuery source code for trigger. In the end, the native DOM method is called, with elem[ type ]();. But it only gets to this point under certain conditions...these are the conditions (among other nested if statements):
if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
And I'm guessing that specifically, the part !(type === "click" && jQuery.nodeName( elem, "a" )) is what prevents it in your case, because the element you're targeting is <a>, and it's the click event.
DEMO: Here's basically just something mimicking your code in a simpler fashion: http://jsfiddle.net/EjVMY/ - notice how the initial console.log on load doesn't execute (because of the trigger). But as soon as you actually click on the event, the console.log does execute. I found that replacing the <a> with a <div> changes the behavior - it logs on load.
Of course, if I had just Googled it in the first place, I would've found: trigger a click on a anchor link
Related
I am working with a very large application with a lot of JavaScript. I am trying to determine how I can find the location where a click event is being removed from a specific element.
There is a simple event listener on a specific field added via jQuery (this is an example).
$(document).ready(function() {
$('#id-name').on('click', function(e) {
window.alert('hello');
});
});
If break execution right after this and examine the element in Chrome Inspector, I see the event attached to the element. However, once I continue execution and the page finishes loading, the element no longer has the event. Something is removing it, but I can't find out where this is happening.
Is there a way to listen for "event removal" and trigger code then, so that I can identify where and how this is getting removed? Any other suggestions in locating where the click event is being removed?
Maybe you could override the removeEventListener method and trace it back to see what's calling it.
window.removeEventListener = (type, listener, useCapture)=>console.trace(type, listener, useCapture)
I have multiple images on my page. To detect broken images , I used this found on SO.
$('.imgRot').one('error',function(){
$(this).attr('src','broken.png');
});
This works fine on the first image which I understand. But when I change this to
$('.imgRot').on('error',function(){
$(this).attr('src','broken.png');
});
it does not work on any of the images . Could someone tell me why ?
Community wiki: This generic answer does not contribute to the question OP posted but relative to the title.
The concept of one() and on() can be explained with the below code.
one() function is automatically moved to off state after first instance of occurance.
on() is identical to one() but it needs to be manually put to off state otherwise the number of instances has no limit.
var i = 1;
$('.one').one('click', function() {
$(this).text('I am clickable only once: ' + i);
i++;
});
var j = 1;
$('.multiple').on('click', function() {
$(this).text('I was clicked ' + j + ' times');
j++;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="one">Click me</div>
<div class="multiple">Click me</div>
If you look at the source code for .one() in jQuery 1.7, it just calls .on() internally except that after the event fires, it removes the event handler. So, there should be no difference in your case because error is an event that should only happen once per object anyway.
So, there must be something else going on in your code like maybe the image objects haven't been loaded into the DOM yet when you run this code or something like that.
If you were trying to use delegated event handling to do this (which your example does not show), then you may run into issues where the 'error' event doesn't propagate.
It may also be that your code has timing issues due to caching. Trying to install these types of error handlers on images that are already in the DOM is a race condition. You're trying to get the error handler installed before it gets called, but the image has already started loading and the event might have already fired before you get the event handler installed. Subsequent page loads (after the first) may have cached other page elements or DNS references so it may get to the error handler quicker and perhaps even before your JS can run and install the error handlers.
I know this is an issue with browser caching and the onload event. You can only reliably get the onload event if you attach the event handler either in the embedded HTML (so it's there when the <img> tag is first parsed or if you attach it before the .src property has been set (if creating the image programmatically). That would suggest that you can't reliably set error handlers the way you are doing for images that are in the page HTML.
My suggestion would be this:
Don't try to install error handlers like this after the images are in the DOM.
If you assign them on programmatically generating images, then assign the event handlers before .src is assigned.
If you need these on images in the page's HTML, then you will have to put the event handlers in the HTML with something like <img src="xxx" onerror="yourErrorFunc(this)"> because that's the only way to guarantee that the handlers are installed before the event can occur.
jQuery will reuse the "on" method for the "one". Following is the internal code of jQuery where they'll be passing hardcoded value "1" to the function of jQuery.on() They'll turn off the triggered event further on the element using jQuery.off()
on:function( types, selector, data, fn, one ) {
if ( one === 1 ) {
origFn = fn;
fn = function( event ) {
jQuery().off( event );
return origFn.apply( this, arguments );
};
}
off:function(types, selector, data, fn){
on(types, selector, data, fn, 1);
}
So, in your case "error" is the event type triggered on the first image and when the jQuery.one() method called this event got turned off and then its not triggered for further on the $('.imgRot') elements
I've made this test code for the question: https://jsfiddle.net/5phqm/1/
As far as I understand, if jQuery's triggerHandler() prevents default browser behavior, then native JavaScript events will not be triggered and handled (and it's true for addEventListener() in my code), but inline event, added through tag's attribute onclick="" will be triggered anyway! Why it happens? Am I misunderstanding something about events triggering in browser?
It can be confirmed that inline handlers are run because it is explicitly coded:
handle = ontype && cur[ ontype ];
if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {
event.preventDefault();
}
where ontype is in this case "onclick". So it is fetching the onclick property of the element and then executing it. This piece of code is always called, regardless of .trigger/.triggerHandler.
Native actions however, like elem.click(), are only executed inside an if block:
if ( !onlyHandlers && !event.isDefaultPrevented() ) {
// ...
elem[ type ]();
where onlyHandlers is true for triggerHandle and false for .trigger, and therefore triggerHandler does not execute e.g. elem.click() (whereas .trigger does). As such, the native action is prevented.
So inline handlers and native actions are separate things and are also handled separately. Only native actions are prevented by .triggerHandler.
I think (but it's a guess, i gave a brief look at jQuery source code and this might be totally wrong) that jQuery retrieves the events attached to elements in jQuery.trigger.event by calling something like
$(elem).data("events");
and then decides if to fire/stop them. Inline events can't be collected this way and so they can't be stopped.
I have a <div> box displaying search message and some radio button for recent message. There is link option for slide toggle.
When you click on that link it will show some input field and check box and radio button. And at the same time the text of link change to hide option. If you click on that it will hide all the input and checkbox option.
When I refreash the whole page its working properly but when that paticular box or part is refreashing then the box is hiding and imediately hides. If you refresh that portion n number of times the box is going on toggling continously. I think the problem is in registration of event handler. So please give me some solution.
CODE :
$(document).ready(function() {
$(".SideBar-blockheader1").click(function() {
e.preventDefault();
$(".SideBar-blockcontent1").slideToggle("fast");
});
$(".SideBar-optionheader").click(function() {
$(".SideBar-optioncontent").slideToggle("fast");
$(this).text($(this).text() == $("#hideopt").attr('value') ? $("#showopt").attr('value') : $("#hideopt").attr('value'));
});
$(".SideBar-optionheader").text($("#showopt").attr('value'));
$(".SideBar-optioncontent").hide();
});
jQuery has a method, called data() which can be used to extract the attached handler information of an HTML element. You can see if the element has already a click handler, and if it has, then stop re-attaching another handler to it.
if(typeof $('#id').data('events').click == 'object')
{
// A click handler is already attached
}
else
{
// No click handler; Attach one;
}
Although you haven't provided code, I suspect you are using .click(). For jQuery 1.7+ you should be using .on() in delegate mode (the element you bind to is an ancestor, not the clickable element itself) or .delegate() if pre jQ 1.7.
For example:
$('someAncestor').on('click', 'a.specialLink', function(event) {
event.preventDefault();
// the rest of your code for the click handler
})
"someAncestor" is any valid selector that is an ancestor of your link that will not be destroyed, rebuilt, or otherwise manipulated after the DOM is built. It doesn't have to be the direct ancestor.
[updated below after seeing code sample and comments]
There are a few things going on. First, .on() will only work if you're using jQuery 1.7+. Next, .on() can be invoked a few different ways (I wrote about it here: http://gregpettit.ca/2011/jquery-events-its-on/) and you need to be invoking it while delegating an ancestor listener, not simply as a substitute for click. Next, you haven't provided code for your attempted update, only for the original code; it's hard to tell what "didn't work" about trying to use .on(). Moving along, I'm not actually sure what this line is meant to do:
$(this).text($(this).text() == $("#hideopt")...etc...
I can't think of why you would want to try to treat a jQuery object as a variable. I'm not saying the code is wrong, I'm just saying I don't get it. Also, I hate ternary operators... which is part of the reason I don't get it. I much prefer readable conditionals. ;-)
Next, you're calling preventDefault() on "e" but you're not passing "e" into your functions. You might just be getting a JavaScript error, period. (e is undefined)
Then there's attr("value") which I believe should actually work. But why not use .val() if it is indeed a node that HAS a value attribute?
Finally, there is tonnes of room for caching your objects. Every time you see that an object is being used more than once, you can benefit (to varying degrees of performance and legibility) from caching it. I have not updated the code with any caching, though-- that's really something for a whole other "How can I best cache my objects?" question.
Anyhow... to solve the problem, you first have to choose a valid ancestor. This can be any ancestor that isn't destroyed during the process of loading in your new data. This could be anything, but the closest ancestor is the best. It might be a section wrapper, but if you're truly desperate it could be a page wrapper or even the body tag. If you bind to document, you're reproducing the deprecated .live() function, which I definitely recommend against. I have used a placeholder selector, ".section" but you need to figure out what an appropriate ancestor is on your page.
$(document).ready(function()
{
$(".section").on("click", ".SideBar-blockheader1", function(e)
{
e.preventDefault(); // probably not necessary if there's no default click behaviour
$(".SideBar-blockcontent1").slideToggle("fast");
});
$(".section").on("click", ".SideBar-optionheader", function(e)
{
e.preventDefault(); // probably not necessary if there's no default click behaviour
$(".SideBar-optioncontent").slideToggle("fast");
$(this).text($(this).text() == $("#hideopt").val() ?$("#showopt").val() : $("#hideopt").val());
});
$(".SideBar-optionheader").text($("#showopt").val());
$(".SideBar-optioncontent").hide();
});
I have a timer in my JavaScript which needs to emulate clicking a link to go to another page once the time elapses. To do this I'm using jQuery's click() function. I have used $().trigger() and window.location also, and I can make it work as intended with all three.
I've observed some weird behavior with click() and I'm trying to understand what happens and why.
I'm using Firefox for everything I describe in this question, but I am also interested in what other browsers will do with this.
If I have not used $('a').bind('click',fn) or $('a').click(fn) to set an event handler, then calling $('a').click() seems to do nothing at all. It does not call the browser's default handler for this event, as the browser does not load the new page.
However, if I set an event handler first, then it works as expected, even if the event handler does nothing.
$('a').click(function(){return true;}).click();
This loads the new page as if I had clicked the a myself.
So my question is twofold: Is this weird behavior because I'm doing something wrong somewhere? and why does calling click() do nothing with the default behavior if I haven't created a handler of my own?
As Hoffman determined when he tried to duplicate my results, the outcome I described above doesn't actually happen. I'm not sure what caused the events I observed yesterday, but I'm certain today that it was not what I described in the question.
So the answer is that you can't "fake" clicks in the browser and that all jQuery does is call your event handler. You can still use window.location to change page, and that works fine for me.
Another option is of course to just use vanilla JavaScript:
document.getElementById("a_link").click()
Interesting, this is probably a "feature request" (ie bug) for jQuery. The jQuery click event only triggers the click action (called onClick event on the DOM) on the element if you bind a jQuery event to the element. You should go to jQuery mailing lists ( http://forum.jquery.com/ ) and report this. This might be the wanted behavior, but I don't think so.
EDIT:
I did some testing and what you said is wrong, even if you bind a function to an 'a' tag it still doesn't take you to the website specified by the href attribute. Try the following code:
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
<script>
$(document).ready(function() {
/* Try to dis-comment this:
$('#a').click(function () {
alert('jQuery.click()');
return true;
});
*/
});
function button_onClick() {
$('#a').click();
}
function a_onClick() {
alert('a_onClick');
}
</script>
</head>
<body>
<input type="button" onclick="button_onClick()">
<br>
<a id='a' href='http://www.google.com' onClick="a_onClick()"> aaa </a>
</body>
</html>
It never goes to google.com unless you directly click on the link (with or without the commented code). Also notice that even if you bind the click event to the link it still doesn't go purple once you click the button. It only goes purple if you click the link directly.
I did some research and it seems that the .click is not suppose to work with 'a' tags because the browser does not suport "fake clicking" with javascript. I mean, you can't "click" an element with javascript. With 'a' tags you can trigger its onClick event but the link won't change colors (to the visited link color, the default is purple in most browsers). So it wouldn't make sense to make the $().click event work with 'a' tags since the act of going to the href attribute is not a part of the onClick event, but hardcoded in the browser.
If you look at the code for the $.click function, I'll bet there is a conditional statement that checks to see if the element has listeners registered for theclick event before it proceeds. Why not just get the href attribute from the link and manually change the page location?
window.location.href = $('a').attr('href');
Here is why it doesn't click through. From the trigger function, jQuery source for version 1.3.2:
// Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
if ( (!elem[type] || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
event.result = false;
// Trigger the native events (except for clicks on links)
if ( !bubbling && elem[type] && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
this.triggered = true;
try {
elem[ type ]();
// Prevent Internet Explorer from throwing an error for some hidden elements
}
catch (e)
{
}
}
After it calls handlers (if there are any), jQuery triggers an event on the object. However it only calls native handlers for click events if the element is not a link. I guess this was done purposefully for some reason. This should be true though whether an event handler is defined or not, so I'm not sure why in your case attaching an event handler caused the native onClick handler to be called. You'll have to do what I did and step through the execution to see where it is being called.
JavaScript/jQuery doesn't support the default behavior of links "clicked" programmatically.
Instead, you can create a form and submit it. This way you don't have to use window.location or window.open, which are often blocked as unwanted popups by browsers.
This script has two different methods: one that tries to open three new tabs/windows (it opens only one in Internet Explorer and Chrome, more information is below) and one that fires a custom event on a link click.
Here is how:
HTML
<html>
<head>
<script src="jquery-1.9.1.min.js" type="text/javascript"></script>
<script src="script.js" type="text/javascript"></script>
</head>
<body>
<button id="testbtn">Test</button><br><br>
Google<br>
Wikipedia<br>
Stack Overflow
</body>
</html>
jQuery (file script.js)
$(function()
{
// Try to open all three links by pressing the button
// - Firefox opens all three links
// - Chrome only opens one of them without a popup warning
// - Internet Explorer only opens one of them WITH a popup warning
$("#testbtn").on("click", function()
{
$("a").each(function()
{
var form = $("<form></form>");
form.attr(
{
id : "formform",
action : $(this).attr("href"),
method : "GET",
// Open in new window/tab
target : "_blank"
});
$("body").append(form);
$("#formform").submit();
$("#formform").remove();
});
});
// Or click the link and fire a custom event
// (open your own window without following
// the link itself)
$("a").on("click", function()
{
var form = $("<form></form>");
form.attr(
{
id : "formform",
// The location given in the link itself
action : $(this).attr("href"),
method : "GET",
// Open in new window/tab
target : "_blank"
});
$("body").append(form);
$("#formform").submit();
$("#formform").remove();
// Prevent the link from opening normally
return false;
});
});
For each link element, it:
Creates a form
Gives it attributes
Appends it to the DOM so it can be submitted
Submits it
Removes the form from the DOM, removing all traces *Insert evil laugh*
Now you have a new tab/window loading "https://google.nl" (or any URL you want, just replace it). Unfortunately when you try to open more than one window this way, you get an Popup blocked messagebar when trying to open the second one (the first one is still opened).
More information on how I got to this method is found here:
Opening new window/tab without using window.open or window.location.href
Click handlers on anchor tags are a special case in jQuery.
I think you might be getting confused between the anchor's onclick event (known by the browser) and the click event of the jQuery object which wraps the DOM's notion of the anchor tag.
You can download the jQuery 1.3.2 source here.
The relevant sections of the source are lines 2643-2645 (I have split this out to multiple lines to make it easier to comprehend):
// Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
if (
(!elem[type] || (jQuery.nodeName(elem, 'a') && type == "click")) &&
elem["on"+type] &&
elem["on"+type].apply( elem, data ) === false
)
event.result = false;
You can use jQuery to select the jQuery object for that element. Then, get the underlying DOM element and call its click() method.
By id:
$("#my-link").each(function (index) { $(this).get(0).click() });
Or use jQuery to click a bunch of links by CSS class:
$(".my-link-class").each(function (index) { $(this).get(0).click() });
Trigger a hyperlink <a> element that is inside the element you want to hookup the jQuery .click() to:
<div class="TopicControl">
<div class="articleImage">
<img src="" alt="">
</div>
</div>
In your script you hookup to the main container you want the click event on. Then you use standard jQuery methodology to find the element (type, class, and id) and fire the click. jQuery enters a recursive function to fire the click and you break the recursive function by taking the event 'e' and stopPropagation() function and return false, because you don't want jQuery to do anything else but fire the link.
$('.TopicControl').click(function (event) {
$(this).find('a').click();
event.stopPropagation();
return false;
});
Alternative solution is to wrap the containers in the <a> element and place 's as containers inside instead of <div>'s. Set the spans to display block to conform with W3C standards.
It does nothing because no events have been bound to the event. If I recall correctly, jQuery maintains its own list of event handlers that are bound to NodeLists for performance and other purposes.
If you need this feature for one case or very few cases (your whole application is not requiring this feature). I would rather leave jQuery as is (for many reasons, including being able to update to newer versions, CDN, etc.) and have the following workaround:
// For modern browsers
$(ele).trigger("click");
// Relying on Paul Irish's conditional class names,
// <https://www.paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/>
// (via HTML5 Boilerplate, <https://html5boilerplate.com/>) where
// each Internet Explorer version gets a class of its version
$("html.ie7").length && (function(){
var eleOnClickattr = $(ele).attr("onclick")
eval(eleOnClickattr);
})()
To open hyperlink in the same tab, use:
$(document).on('click', "a.classname", function() {
var form = $("<form></form>");
form.attr(
{
id : "formid",
action : $(this).attr("href"),
method : "GET",
});
$("body").append(form);
$("#formid").submit();
$("#formid").remove();
return false;
});