In the MouseEvent class there are multiple *Target events:
target
currentTarget
relatedTarget
What is their purpose in the context of a MouseEvent?
These properties are equivalent to the JavaScript mouse events. JavaScript events traverse the DOM (called "bubbling"). target is the object on which the event was originally dispatched on. currentTarget is the object on which your event handler has been attached.
Example
You have this HTML structure:
<ul id="list">
<li>Entry 1</li>
<li>Entry 2</li>
</ul>
and you add a click handler to the <ul> element (either via JavaScript or Dart, the concept is the same).
When you then click on "Entry 2", your click handler will be called (because the event "bubbles up" to it). target will be the <li> element, while currentTarget will be the <ul> element. Which one you have to use depends on what you want to do in your handler - for example, you could hide "Entry 2" itself by using target, or the whole list by using currentTarget.
The element referenced by relatedTarget depends on the type of your MouseEvent - a list can be found here: event.relatedTarget. In the above example, it would be null, because click events don't have any related target.
Related MDN links:
event.currentTarget,
event.target
Related
Given ul list defined as below:
<ul click.delegate="onListItemClick()">
<li repeat.for="suggestion of suggestions">
${suggestion.name}
</li>
</ul>
How do I pass suggestion object to onListItemClick? I know I can put click.delegate on each individual li element and then capture current suggestion but won't it go against event delegation idea? I mean - then I will have multiple event handlers attached, and if so I could just go with click.trigger. I don't want to do this, because there may be tons of these suggestion objects.
Put the click handler on the li element. That's the whole point of event delegation with Aurelia. It allows you to do stuff just like this without the overhead of creating a bunch of event handlers. There's just one event handler that is created by the framework for you. It delegates the calls. All of the elements click event will be set to the same function and Aurelia will handle calling your VM method.
Here's a gist.run: https://gist.run/?id=406bf3bc73e415db7afa7d46d7e958d3
<template>
You clicked suggestion id "${clickedId}"
<ul>
<li repeat.for="suggestion of suggestions" click.delegate="handleClick(suggestion)">
${suggestion.name}
</li>
</ul>
</template>
I am struggling to understand how Meteor adds event bindings to templates.
I have a template with multiple anchors for the navigation dropdowns:
<template name="user_loggedin">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Select a profile..
<b class="caret"></b></a>
<ul class="dropdown-menu">List</ul>
</li>
<li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">
<i class="glyphicon glyphicon-cog"></i>
<b class="caret"></b></a>
<ul class="dropdown-menu"> </ul>
</li>
</template>
And I try to bind a click event to show the dropdown menus:
Template.user_loggedin.events({
"click a.dropdown-toggle": function(e,tml) {
$(e.target).siblings('.dropdown-menu').toggle()
}
})
However, the event only seems to bind to the first anchor element, not all of those matching the 'a.dropdown-toggle' selector.
The same problem occurs for templates containing dynamic elements derived from collections. I'd just assumed the Meteor template events method would work in the same way as $('a.dropdown.menu').on(...
I suspect this is to do with Meteor not having rendered all the template's DOM elements before the events are bound. I've seen solutions using Meteor.template.rendered to bind events after rendering, but this seems messy considering Meteor are deprecating rendered method in the next release.
Is there another way?
No. The event handler is specified for the template and is not "bound" to an element. So your event handler will definitely be executed if any anchor element with class dropdown-toggle is clicked.
The problem you are experiencing is probably caused by the use of e.target instead of e.currentTarget in your event handler. From the Meteor docs:
target
The element that originated the event.
currentTarget
The element currently handling the event.
This is the element that matched the selector in the event map. For
events that bubble, it may be target or an ancestor of target, and its
value changes as the event bubbles.
In the first case both e.target and e.currentTarget are a.dropdown-toggle and everything works as expected. In the second case, however, e.target is i.glyphicon.glyphicon-cog while e.currentTarget is a.dropdown-toggle (which is what you want to have).
So please try to edit your event handler to look like this:
Template.user_loggedin.events({
"click a.dropdown-toggle": function(e,tml) {
$(e.currentTarget).siblings('.dropdown-menu').toggle()
}
});
About your second problem with the dynamic elements: can you provide an example?
I have created a simple div demonstration below, that will display none once click.
<div id="three" onclick="toggle2(event);return false;" style="background:#303; color:#FFF;">
function toggle2(e) {
var textx = (e.target) ? e.target : e.srcElement;
textx.style.display = "none";
console.log(e.target);
}
my question is what is the difference if I replace
<div id="three" onclick="toggle2(event);return false;" style="background:#303; color:#FFF;">
with
<div id="three" onclick="toggle2(this);return false;" style="background:#303; color:#FFF;">
both of them work fine for my example abovee.....
It may well be that they are exactly the same. This depends on the HTML. In this case, this will always be the div element. this refers to the element where the event is captured. event.target, however, points to the element where the event originated.
If the element has no children, they will always be the same. If, however, you had something like this:
<div id="three" onclick="toggle2(event);return false;" style="background:#303; color:#FFF;">
<span>Line 1</span>
Line 2
</div>
then they may be different. A click on Line 1 will cause event.target to be the span element, so only that element will be hidden.
Unless you specifically want to point to the element where the event originated, it's more intuitive to use this.
You usually use e.target when "e" is the event like a click passed in parameter.
When you pass this as a parameter, this is the reference to the DOM node in which there is the javascript method. So here, "this" references the div.
And as you have a click event on your div, when you click on it, it is considered as an event, that's why this and e.target both work.
Moreover, "this" will always refer to you div, whereas "e.target" will reference an element you clicked in the div.
I think isn't necessary to pass this as argument on onclick event, you can use this direct to the function.
The event refers to the event currently being fired. Now in a browser the events are bubbled up from the element on which the event is fired to its parent until it reaches the document root. More at: What is event bubbling and capturing?
In your example, the event points to the click event and the event.target is the div and this refers to the div itself. If you add a child element to the div and click on the element then the event.target will point to the child element and this will still refer to the div.
Background
I have been using Backbone.js for some time and one aspect of it that impresses me is how it allows me to simplify, abstract and reuse DOM elements as 'views'. I have tried to read through some of the annotated source and am familiar with JQuery, but have little knowledge of how the DOM works on a deeper level.
Question
How does Backbone.JS tie DOM elements to views without assigning an id, class or other attribute to them?
i.e.
<ul>
<li>Item one</li>
<li>Item two</li>
<li>Item three</li>
</ul>
I love that Backbone does this and would like to know how it does it!
In javascript, a variable can hold a reference (i.e a programmatic thing that "refers to") to some element of the DOM, which is just a Javascript object. Backbone makes sure that for a view, at least that element exists. For example, in jQuery, when you refer to the third item in your list:
var item3 = $('ul li').eq(2);
(It's a zero-offset list, the first item is at index 0, the third at index 2), you can now change the text from "Item three" to "Item three point one four one five nine" with ordinary jQuery DOM manipulators:
item3.text("Item three point one four one five nine");
Even though that list item doesn't have any particular class or ID attributes.
A backbone view's el field contains a constant reference to the parent element in which that view renders all of its stuff. Backbone uses the jQuery delegate event manager to attach a generic event handler to that one constant reference. Whenever an event happens within that DOM element or any of its children, the delegate catches the event, along with a reference to the specific DOM object within the parent el that created the event, and backbone uses some fairly standard jQuery magic to map that to an event handler in the view.
It is, indeed, very cool stuff.
I should add that the "constant"-ness of the el reference is, er, arguable. If you're attaching view logic to an existing HTML element, you do assign to the el once, in the view's initialize(). Javascript doesn't enforce any notion of constantness, but you should only directly assign to el (ie this.el = something()) if you're sure you know what you're doing.
Forewarning: I'm a newbie to JQuery.
I have a collection of links and lists that look something like so. They're dynamically generated by my back end framework...
<ul>
<li>
<a id="link1" class="special" href="#">...</a>
<ul id="list1"> ... </ul>
</li>
<li>
<a id="link2" class="special" href="#">...</a>
<ul id="list2"> ... </ul>
</li>
<li>
<a id="link3" class="special" href="#">...</a>
<ul id="list3"> ... </ul>
</li>
</ul>
I'm trying to learn JQuery and Unobtrustive Javascript, so I want to add a click handler on all the links with the class "special" that will toggle the related lists.
So...
$(document).ready(function() {
$("a.special").click(function() {
id = *magicFunctionToGetOwnID*
$(convertListIDtoLinkID(id)).toggle
})
})
What is the magic function that I need? What about if I want to get other properties of the thing I'm attaching a handler to? Say, in the future, I add a "toggle-target" property and I would want to get that?
Not sure If I get you right, but it looks like you want something like this:
$(function() {
$('ul:first').delegate('a.special', function( event ) {
$(this).next('ul').toggle();
});
});
You don't should bind an event handler to all nodes in a situation like that. It's enough to bind one handler to a shared parent and make use of the event bubbling.
Update
.delegate() does exactly what I described above. It'll bind the event handler to a node. The trick is, that event if that event is triggered on a child node from the delegated node, the events will "reach" our destination by bubbling up the DOM tree (unless explicitly prohibit event bubbling). However, jQuery is nice and will always bind this to the target node (the node which originally received the event).
Have a read: http://api.jquery.com/delegate/
Try $(this).parent().find("ul").toggle(). It is rather self-explanatory.
http://jsfiddle.net/gLu9a/
The way to get an element's own id is with the id property. The element that was clicked is set as this within the handler, so you can use this.id.
That said, this is not an optimal technique. Use DOM relationships, rather than setting ids, wherever you can. This will make your code more flexible and intuitive. In this case, you can use the next method, to get the DOM element that follows the element that was clicked:
$(this).next().toggle();
See the API "traversing" category for more ways of adjusting a selection.