How does $(this) know what my target is? - javascript

How does $(this).keyup know I want the keyup listener associated with the #searchString input, and not the parent div? Doesn't $(this) represent the parent div? I dumped out $(this) to the console, and it looks like an object for the parent div.
Long story short:
How is this working? $(this).keyup
Instead of explicitly saying: $('#searchString').keyup ??
$('<div id="msg">' + <input id="searchString" name="searchString" type="text" value="" /> + '</div>').dialog({
open: function () {
$(this).keyup(function (e) {
if (e.keyCode == $.ui.keyCode.ENTER)
$('#btnFind').click();
return false;
})
},
buttons: [
{
text: "Find",
id: "btnFind",
icon: "ui-icon-search",
click: function () {
//do stuff
}
}
]
});

Did some testing; here are my observations:
$(this) is representative of the parent <div id="msg">
$(this).keyup is targeting any (and all) extra inputs I add to <div id="msg">
I don't think this this is event bubbling/capturing (the listeners are not nested):
$('#btnFind').click(); is an action nested inside the keyup listener
the jQuery UI dialog button id: "btnFind" has a separate event listener, outside of the the parent <div id="msg">
I went ahead and explicitly indicated the target for the listener: $('#searchString').keyup
Who cares?
Well, I didn't think you could establish event listeners on inputs via the dialog open event. I'm creating my dialog on-the-fly, and my assumption was that the input may not exist while the open event was trying to establish the event listener.

Related

How to listen for event on other element

(I asked similiar question yesterday but it went in another direction so posting again with more details)
I have a class/object that takes an ID of a html element, and then sets event handlers on said element.
like: batman.on("click",run_this_code());
The result of that is obviously to run the func/code when the elements click event is fired.
Now, my question is: How can I listen/watch for OTHER elements events?
say batman is a <button id="batman"> and superman is a textfield <input type="text" id="superman">
And I have an instance of my class as described above, for the button "batman".
How would I in that instance, listen for events on "superman".
pseudo code:
batman.listen("click","fired on element with ID superman",run_this_code());
The only thing I have come up with, which I dont know 100% how to do is to register all clicks on the document, with:
var arr;
document.addEventListener('click', function (event) {
if (!event.target.hasAttribute('track_me')) return;
// code here that saves the click, and the ID, into an array (arr)
}, false);
and now other instances can somehow check for changes on the array (arr), and react accordingly.
Ok enough rambling, basically how can i do:
batman.listen("click","on_superman",function(){
alert("this instance represents the 'batman' element, but the element 'superman' was just clicked.");
}
);
I do NOT want to write the code in the "superman" instance. That is just an example, I want to to be a universal function for my class, to listen for events on other instances.
say batman is a <button id="batman"> and superman is a textfield <input type="text" id="superman"> And I have an instance of my class as described above, for the button "batman". How would I in that instance, listen for events on "superman"
You can get a reference to the superman element like this:
document.getElementById("superman")
or if you're using jQuery, as you seem to be, you can get a jQuery object containing that element like this:
$("#superman")
Then use addEventListener (on the element) or on (on the jQuery object) to listen for the click event.
document.getElementById("superman").addEventListener("click", function() {
// superman clicked
});
or
$("#superman").on("click", function() {
// superman clicked
});
The code doing that can be in any class or object method you want.
In a comment you've said:
my goal is to have a function to react to any other elements events
You may be looking for event delegation: Most events bubble, and so you can put an event listener on some container (document itself if you want) and watch for the events to happen. The element that triggered the event is available as the target property of the event object your handler receives:
document.addEventListener("click", function(e) {
// Use `e.target` here...
});
Example:
document.addEventListener("click", function(e) {
console.log(e.target.id + " click");
});
document.addEventListener("input", function(e) {
console.log(e.target.id + " input: " + e.target.value);
});
<div>
<input id="one" type="text">
</div>
<div>
<input id="two" type="text">
</div>

Detect click event in any nested element of an specific div

I need to be able to detect any click that happens within a specific container referenced by class, if the user clicks on any of the nested elements I should be able to detect the click and update a flag
<div class="container" >
<div class="x1">
<div class="x2">
<div class="">
<span class="">
<ul class="">
</div>
</div>
I tried using jquery but I prefer to do it using backbone.
//$(document).on('click','.container', function(e){
//$('.container').delegate("div", "click", function(e) {
Not sure what event I need to use when the users are clicking in some of the nested elements within the div that have the container class. Basically, I need to update a flag in case of the user clicks outside of this div, but I don't want to have a large scope on the event handler that listens to the whole body.
Since you asked for a Backbone example, here's how to listen to clicks on a div and its children.
var View = Backbone.View.extend({
className: "my-test-view",
template: '<div class="container"><div class="x1"><div class="x2">test</div></div></div>',
events: {
'click .container': 'onClick',
},
render: function() {
this.$el.empty().append(this.template);
return this;
},
onClick: function(e) {
console.log("clicked on", e.target, " triggered from ", e.currentTarget);
},
});
var view = new View();
$("body").append(view.render().el);
Clicking the test text should output:
clicked on <div class=​"x2">​test​</div>​ triggered from <div class=​"container">​…​</div>​
With jQuery, the above is (roughly) the equivalent to:
$('.my-test-view').on('click', '.container', function(e) {
console.log("clicked on", e.target, " triggered from ", e.currentTarget);
});
But for most case, this should be enough:
$('.container').on('click', function(e) {
console.log("clicked on", e.target, " triggered from ", e.currentTarget);
});
Don't use .children().on(...) as this will create a new listener for each child and it's inefficient.
Detecting a click outside a div is quite different and there are many ways to achieve it but none is perfect.
See :
Backbone view with custom event to detect clicks outside of it
How to detect a click outside an element?
Use jQuery to hide a DIV when the user clicks outside of it
Personally, I used focus and blur events (don't forget tabindex="-1" on the element).
Maybe this?:
$(document).on('click','.container *', function(e){
console.log(e.target);
});
The great thing about jQuery is that you can use the same selectors as you would use with CSS hence I used .container * to target all elements inside the container.
I used the jquery .children() method. Check out this code pen.
var flag = 'whatever';
$(.container).children().on('click', function() {
flag = 'updated';
});
Essentially, saying for all children of whatever element is class container (div in this case) add an event handler.

DevExpress (JS / HTML) Attach Events to Elements in a Popup

How do you properly attach events to elements in a popup?
This is how I currently do it:
HTML
<div id="userDetail">
<input id="checkbox" type="checkbox" />
<div id="button-confirm"></div>
</div>
JavaScript
var userDetail = $("#userDetail").dxPopup({
width: '550',
height: 'auto',
showTitle: true,
title: "Setup Import Template",
visible: false,
onShown: function () {
$('#checkbox').one('click', function () {
$('.template-view').toggle();
});
$("#button-confirm").dxButton({
onClick: function (e) {
e.jQueryEvent.preventDefault();
templateDataPopup.hide();
}
});
}
}).dxPopup('instance');
The problem with this is that:
Every time the popup is shown, the jQuery attaches new click event to #checkbox element, event after I use .one().
#button-confirm element's click event is NOT being attached twice. This is the behavior I want (although it's not what I expected, I think because it's a DevExpress instance).
I have tried attached events to elements in the popup before I initialized the popup, but for some reason, after the popup is shown, none of the elements' events work.
So, how do you properly attach events to elements in a popup?
Thanks!
I got answer from DevExpress support and the suggestion is to use contentTemplate. The reply:
Use the contentTemplate property to create popup content and add the
required events to it:
contentTemplate: function (contentElement) {
contentElement.append('<input id="checkbox" type="checkbox" />');
var hideButton = $("<div id='button-confirm'>").dxButton({
text: "Hide popup",
onClick: function (e) {
popupInstance.hide();
}
});
contentElement.append(hideButton);
}
So, instead of attaching the event through onShown event, it's recommended to attach in contentTemplate.
You can also load popup content from HTML tag in contentTemplate

Meteor Event Selectors for more complex events

I am trying to get a event handler in meteorjs to work as expected:
The White box should be clickable, if it is clicked, I need to call a function that closes or opens a chapter
when clicking the greyish text (which is a contenteditable <div>) you should be able to edit that contenteditable and has a class .editable
My Problem: I have declared an event handler like this:
Template.chapterBox.events:
'click .chapter-box': (e) ->
do_some_stuff()
how would it be possible to prevent that above event handler from firing when I click the contenteditable to edit it?
I already about something like this in the first line of the event handler
if $(e.target).hasClass("editable"):
return;
but it did not work
You can do something like this:
<template name="ChapterBox">
<div class="chapter-box">
<div class='editable'>Text</div>
</div>
</template>
Template.ChapterBox.events({
'click .chapter-box': function (event, template) {
event.stopPropagation();
console.log("clicked chapter-box: ", event.currentTarget);
},
'click .editable': function(event,template){
event.stopPropagation();
console.log("clicked editable: ", event.currentTarget);
}
});
Check this MeteorPad for a working example.
Event.stopPropagation() prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.
I had the same problem, this worked for me:
if (e.target.className == "editable") {
console.log("clicked editable");
} else {
console.log("clicked chapter-box");
}

click outside DIV

<body>
<div id="aaa">
<div id="bbb">
</div>
</div>
</body>
$(#?????).click(function(){
$('#bbb').hide();
})
http://jsfiddle.net/GkRY2/
What i must use if i want hide #bbb if user click outside box #bbb? But if i click on div #bbb then box is still visible - only outside.
$('body').click(function(e){
if( e.target.id == 'bbb' )
{ return true; }
else
{ $('#bbb').hide(); }
});
A note of explanation: There are a few ways to do this, either way we need to listen for a click on a parent element, weather it be a direct parent like #aaa or a distant parent like the body or the document. This way we can capture clicks that occur outside of #bbb.
Now that we have that we need the .hide to NOT occur if the user did click inside of #bbb. We can do this two ways
Stop propagation if the user clicks on #bbb. This will make the click event not 'bubble' up to the parent. That way the click event never reaches the parent and so #bbb will not hide. I personally don't like this method because stop propagation will so ALL click events from bubbling, and you may have click events that you would like to bubble to a local parent and not a distant parent. Or you may have listeners delegated from a distant parent, which will stop working if click propagation is stopped.
Check for the #bbb element in the parent listener. This is the method shown above. Basically this listens on a distant parent, and when a click occurs it checks to see if that click is on #bbb specifically. If it IS NOT on #bbb .hide is fired, otherwise it returns true, so other things that may be tied into the click event will continue working. I prefer this method for that reason alone, but secondarily its a-little bit more readable and understandable.
Finally the manner in which you check to see if the click originated at #bbb you have many options. Any will work, the pattern is the real meat of this thing.
http://jsfiddle.net/tpBq4/ //Modded from #Raminson who's answer is very similar.
New suggestion, leverage event bubbling without jQuery.
var isOutSide = true
bbb = documment.getElementById('bbb');
document.body.addEventListener('click', function(){
if(!isOutSide){
bbb.style.display = 'none';
}
isOutSide = true;
});
bbb.addEventListener('click', function(){
isOutSide = false;
});
Catch the click event as it bubbles-up to the document element. When it hits the document element, hide the element. Then in a click event handler for the element, stop the propagation of the event so it doesn't reach the document element:
$(function () {
$(document).on('click', function () {
$('#bbb').hide();
});
$('#bbb').on('click', function (event) {
event.stopPropagation();
});
});
Here is a demo: http://jsfiddle.net/KVXNL/
Docs for event.stopPropagation(): http://api.jquery.com/event.stopPropagation/
I made a plugin that does this. It preserves the value for this where as these other solutions' this value will refer to document.
https://github.com/tylercrompton/clickOut
Use:
$('#bbb').clickOut(function () {
$(this).hide();
});
You can use target property of the event object, try the following:
$(document).click(function(e) {
if (e.target.id != 'bbb') {
$('#bbb').hide();
}
})
DEMO
This will work
$("#aaa").click(function(){
$('#bbb').hide();
});
$("#bbb").click(function(event){
event.stopPropagation();
})​
Becouse bbb is inside the aaa the event will "bubbel up to aaa". So you have to stop the bubbling by using the event.stopPropagation when bbb is clicked
http://jsfiddle.net/GkRY2/5/
OK
* this is none jquery. you can easly modify it to work with IE
first create helper method to facilitate codding don't get confused with JQuery $()
function $g(element) {
return document.getElementById(element);
}
create our listener class
function globalClickEventListener(obj){
this.fire = function(event){
obj.onOutSideClick(event);
}
}
let's say we need to capture every click on document body
so we need to create listeners array and initialize our work. This method will be called on load
function initialize(){
// $g('body') will return reference to our document body. parameter 'body' is the id of our document body
$g('body').globalClickEventListeners = new Array();
$g('body').addGlobalClickEventListener = function (listener)
{
$g('body').globalClickEventListeners.push(listener);
}
// capture onclick event on document body and inform all listeners
$g('body').onclick = function(event) {
for(var i =0;i < $g('body').globalClickEventListeners.length; i++){
$g('body').globalClickEventListeners[i].fire(event);
}
}
}
after initialization we create event listener and pass reference of the object that needs to know every clcik on our document
function goListening(){
var icanSeeEveryClick = $g('myid');
var lsnr = new globalClickEventListener(icanSeeEveryClick);
// add our listener to listeners array
$g('body').addGlobalClickEventListener(lsnr);
// add event handling method to div
icanSeeEveryClick.onOutSideClick = function (event){
alert('Element with id : ' + event.target.id + ' has been clicked');
}
}
* Take into account the document body height and width
* Remove event listeners when you don't need them
$(document).click(function(event) {
if(!$(event.target).closest('#elementId').length) {
if($('#elementId').is(":visible")) {
$('#elementId').hide('fast');
}
}
})
Change the "#elementId" with your div.

Categories

Resources