Events handling in prototype.js library - javascript

I found that prototype.js library provides Event handling mechanism, but I can't figure out what's wrong with the following code snippet:
<div>
<div id="foo">Bla-bla</div>
</div>
<script type="text/javascript">
function onFooKeyup(e)
{
var element = e.element();
if (e.keyCode == Event.KEY_ESC)
element.innerHTML="TEST";
}
//document.observe('keydown', onFooKeyup);
$('foo').observe('keydown', onFooKeyup);
</script>
Basically I want to change content (or do styling, etc.) of certain div block when user press escape button. The problem is that observing the foo id doesn't lead to any action, while observing the document (commented line) indeed trigger the change. If I replace my foo div block with input tag, e.g.
<div><input type="text" id="foo" /></div>
then the events will be triggered correctly. Is it a bug?

This is because the event has not originated inside the <div> element, so you can't observe it (listen to it) there. In the case of the <div> block with an <input> tag, the event is actually originated inside that element (if the input has user focus, I think, but it's not relevant here). So no, it's not a bug.
Just catch the keyboard event at document level, because the key events will originate on different elements (different browsers manage this on different ways) but they will all bubble up to the document (unless you stop the event's propagation).

Man, I think the only error is because you are saying to jQuery to look for a tag named 'foo', and then bind the 'keypress' event to it. If you want it to search for your id 'foo' you should do the following
$('#foo').observe ....

Related

Setting the focus into input field

I'm trying to set the cursor into the input field. I'm using the functions focus() and select() but I don't know why it isn't working.
Any ideas?
<input type="text" id="test">
<p onmousedown="press()">Test</p>
<script>
function press() {
let input = document.getElementById('test');
input.focus();
input.select();
}
</script>
This was an interesting question that had me investigating a fair bit about the default behaviour of the mousedown event and the differences between that and click. Thanks!
The answer can actually be explicitly found in the Notes section of the MDN documentation for mousedown:
If you call HTMLElement.focus() from a mousedown event handler, you must call event.preventDefault() to keep the focus from leaving the HTMLElement
So to fix, do exactly that. Note that I've slightly rewritten your code in order to do that, using addEventListener to bind a JS function to the event, which then takes the event object as a parameter. (You could I think have done it your way using the global event object - but it's a bad idea to use that. Using addEventListener rather than inline JS that evaluates a string attribute and executes it as JS is also a much better, more modern approach.)
<input type="text" id="test">
<p id="button">Test</p>
<script>
button.addEventListener("mousedown", press);
function press(event) {
event.preventDefault();
let input = document.getElementById('test');
input.focus();
input.select();
}
</script>
The reason I believe this is necessary is that the mousedown event must have a default handler that causes the focus to go on that particular element - and this overrides your attempt to programatically place the focus elsewhere. I'm not 100% sure on that, but it's the most likely explanation that I can come up with.
Note that your original code works completely fine if you'd used the click event rather than mousedown - and this is more usual. The difference is that click only fires when the user releases the mouse button after the initial press, whereas mousedown fires instantly when the press happens. I can't see why this distinction would ever be important, and unless for some reason it's vital to you, I would recommend using click instead, rather than the fix above.

Why doesn't .on() work for links that weren't preloaded on the page?

After trying hashchange and finding out it simply doesn't work in Internet Explorer, I decided to try a click() approach instead. What below is supposed to do is when a link is clicked, check to see if the url contains the page, then change the link_content's html to a div content with an id equal to the hash.
It works for all links that are preloaded with the page, but the current links in the link_content div do not trigger. Why isn't this working?
$(document).ready(function() {
$('a').on("click", function(event){
if (location.pathname.search("boh.html")){
hash=this.hash;
if(hash=='#more'){
$('#link_content').html($('#hiddenlist').html());
}
else if(hash){
$('#link_content').html($(hash).html());
}
}
});
});
Try:
$(document).on("click", "a", function (event) {
// Your function stuff
});
This is the delegation feature of the on method. It allows you to bind the event to a container element, but the callback function will only execute for elements designated by the selector you provide in the second parameter. Using document as the main selector for this scenario probably isn't the best (although it should work fine), and I think you should use:
$("#page_container").on("click", "a", function () {
Try to narrow down the main selector to a container element that you want this event to be bound to for its containing <a> elements. I guess even "body" could work, and I'm not sure which is preferred between "body" and document. Here's what I mean:
<body>
<div id="main1">
header stuff, no <a> elements
</div>
<div id="main2">
main content, definitely contains <a> elements
</div>
</body>
In this scenario, I would use $("#main2").on("click", "a", function () { because it narrows down the area where the event could occur (and hopefully reduces the processing by jQuery when a click event occurs).
Here's the on signature: http://api.jquery.com/on/#on-events-selector-data-handlereventObject
The reason why this works is because the event is bound to the container, which is not (shouldn't be) dynamic and will always be available (and therefore the event will always be bound). When the specific event, "click" in your case, is triggered from an element inside the container, it bubbles up the container and that's where this event comes into play. The event will determine if the element that triggered the event matches the second parameter selector (if provided) and execute the event in its context if so.

How to prevent HREF (which calls JS function) from being triggered when "Enter" key is pressed?

I am facing a problem.
I have a href which calls a javascript function "delete_element_on_page" when i click on it.
So when i click the HREF with my mouse, everything is fine and the function gets called.
However, because the HREF has focus, if keep hitting my enter key, the function gets called again and again and again leading to undesired outcomes.
How can i prevent this from happening?
I was thinking of
1. Blurring the focus on the href when my function is called
--> I could do this, but this will mean I have to manually do this for every single HREF because jquery.blur can only be triggered at an individual element level.
--> Alternatively, is there a javascript equivalent of where I can do a universal Blurring, regardless of which element is in focus?
OR
Deactivate enter key from triggering clicking of a HREF
--> Is this even possible? And if so, worth my while in terms of code complexity / compatibility etc..
Thanks so much :)
You can bind your event and avoid placing the javascript trigger inside the html tag.
With jQuery (the easy and more reliable way) you do that like this:
<script src="http://code.jquery.com/jquery.min.js"></script>
<script>
$("#myelementid").bind("click",function(e){
e.preventDefault(); // important, to prevent trigering the default a href
// your code goes here
$(this).blur();
});
</script>
The above answers will block both keyboard click and mouse click this will block the enter key from doing anything on that link. So it corresponds to #2
<a id="fail" href="http://jquery.com">default click action is prevented</a>
<script>
$("#fail").keydown(function(event) {
event.preventDefault();
});
</script>
you can bind click event handle it by jquery, using href for calling js functions is not recommended:
$("a#id").click(function(){
// the code goes here;
})

DOM/jQuery events propagation differences between input types

As we know, returning false from a DOM event handler will stop the propagation of the event. But I recently discovered that the behavior of different elements varies with respect to this event. For example, consider the following:
<div id="container">
<input type="checkbox" name="foo" value="1" /> Check me!
<br />
<select>
<option>1</option>
<option>2</option>
<option>3</option>
</select>
<br />
<input type="text" size="30" />
</div>
The surrounding container has a click handler that returns false:
$('#container').click(function(e) {
$('#clicks').append('<span>clicked</span>');
return false;
});​
Within the div, I can still click on the text box and enter text, and can still click on the dropdown to change its value. But clicking on the checkbox does nothing (actually, that's not quite true - it checks the box, fires the handler, then unchecks it). jsfiddle here: http://jsfiddle.net/4ncaq/
This behavior is consistent across browsers so I assume it's by design. But what exactly is the rule that's at work here? How can I know how other kinds of elements might behave in this type of scenario?
What you are seeing is propagation, events 'bubble' up the DOM, so when you click your checkbox it is actually firing the click event on #container (as well as any events you might have bound to the input or other parent elements).
Using return false like this is ambiguous because it is doing 3 things at once, when you most likely only want it to do one. It prevents the default functionality, halts propagation and stops further execution.
It is better practice to be specific and use the methods from the event object to prevent the default action or stop bubbling.
event.preventDefault() will stop things like loading the href from an anchor click, stopping a checkbox from being checked etc.
event.stopPropagation() will cancel propagation, this is useful for situations like your example - http://jsfiddle.net/4ncaq/1/
The other problem with return false is that it may not be executed, a common mistake I see people make in jQuery is having a click event on an anchor with an $.ajax() request followed by return false to stop the browser from loading the linked page. In this scenario, if there is an error coming from ajax() (not a response error, a jQuery error - usually a misspelt param or something) it will never hit return false; and the browser will load the linked page. Using e.preventDefault() entirely removes this problem.
When you click an element, the event will continue propagating the event until some handler decides to cancel the propagation. In this case, when you click the checkbox, it will raise the event for the <input> first and then propagate to #container where you are stopping propagation.
If you want to cancel the propagation from input elements such as checkboxes or textareas you should bind to their click event and stop propagation at that point.
Edited
return false also cancels the default action for the original target element. Checkboxes, links, radio buttons are some of the elements where the default click action is cancelable. The default action for the click event in a checkbox toggles the value of the checkbox while there is no default click action for the select which means it does not get cancelled.
I've tried to find a list of default actions without luck but you can check the links at Is there a standard resource for the "default action" of HTML elements?.

Can I call jQuery's click() to follow an <a> link if I haven't bound an event handler to it with bind or click already?

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

Categories