Detecting mouse click on div with Javascript without side-effects - javascript

I want to detect whenever someone clicks in a div (essentially I want to know when a user is interacting with a section of text on my site, be that by selecting some text or clicking on a link), but I don't want to interfere with what the user is doing.
If I put a onmousedown or onclick event on the div it ends up breaking selection, links, etc. Is there any way to catch these events without causing any interference ?

Onmousedown or onclick shouldn't interfere with anything as long as it doesn't return false;.
You can do this:
document.getElementById("spy-on-me").onmousedown = function () {
console.log("User moused down");
return true; // Not needed, as long as you don't return false
};
If you have other scripts that are attaching behaviour via this method on the page, then to prevent overriding them you can do:
var spyElement = document.getElementById("spy-on-me");
var oldMousedown = spyElement.onmousedown;
spyElement.onmousedown = function () {
console.log("User moused down");
if(oldMousedown) oldMousedown();
};

Yes, I suspect you are currently returning false at the end of the event binding, just don't do that or any of the things in this binding:
$('a').click(function(e) {
e.stopPropagation();
e.preventDefault();
return false;
});
If you do not do any of these three things, jQuery will not stop the event from bubbling up to the browser.
Edit: Sorry didn't realise it was a plain JavaScript question.

you can use do it by adding a event listener as well
var myNode= document.querySelector('.imagegrid');
myNode.addEventListener("click",function(e){
alert(e.target+" clicked");
});
A similar example is demonstrated here

Can't you simply add a click event to the div?
<div id="secretDiv" (click)="secretDivClick()">
then on your component:
secretDivClick() {
console.log('clicked');
}

Related

Detecting the event that causes focus of HTML span tag

I need to determine the event that causes the focus of an HTML span tag. The span tag is a glyhpicon from bootstrap v3.
Right now, I have a .focus() event handler attached to the span tag to catch when the focus occurs but I can't figure out how to tell if the focus was caused by a click or a tab.
HTML tag: <span class="glyphicon glyphicon-ok-circle col-xs-6"></span>
Jquery:
$("span").focus(function (e) {
var event = "click" //This "event" var is the event that caused the focus
if(event == "click"){
//do something
}else{
//if not a click event, do something else
}
});
Do I use the eventData(e) parameter to detect this?
So far, I haven't been able to find the property that shows what caused the focus inside the eventData(e) parameter. The "originalEvent" property only returns "focus" and not what caused it.
Edit: The answer in Differentiate between focus event triggered by keyboard/mouse doesn't fulfill my question. That user is trying to find whether a click or keyboard event occurs on a jquery "autocomplete" element. I need to find the event that causes the focus on a span tag... not an input tag. The ".focus()" event of the element occurs before all other events.
Answer: Check my post below.
$('span').on('focus', function(e){
$( 'span' ).mousedown(function() {
alert( "focus using click" );
});
$(window).keyup(function (e) {
var code = (e.keyCode ? e.keyCode : e.which);
if (code == 9) {
// Using tab
}
});
});
I appreciate everyone's feedback! The answer suggested in the comments helped to partially solve the problem. However, I can't give full credit because it didn't fully answer the question.
The answer suggested in the link was to create a "click" and "keypress" event to update a flag that would be checked on the ".focus()" event to determine the source of how it was triggered. My scenario was more complex. The ".focus()" event occurs before a "click()" event... so the flags wouldn't trigger until after the focus has already occurred and passed. The answer also suggested using a "setTimeout()" to make the focus event wait.. which I found unnecessary in my conclusion.
Conclusion
After some research, it was apparent that a ".mousedown()" event occurs before the ".focus()" event. Using the binded flags listed in the suggested answer above, I created the code below to solve my problem.
$(document).bind('mousedown', function () { isClick = true; }).bind('keypress', function () { isClick = false; });
$("span").focus(function () {
if (isClick) {
//Focused by click event
} else{
//Focused by keyboard event
}
});
I also noticed during research that ".bind()" has been deprecated in Jquery v3.0... so I will be switching my code to read:
$(document).mousedown(function () { isClick = true; }).keypress(function () { isClick = false; });
$("span").focus(function () {
if (isClick) {
//Focused by click event
} else{
//Focused by keyboard event
}
});
Please add any comments/suggestions/optimizations as a comment to my answer! Would love to hear other input.

Is it possible to emit an event using a standard HTML button?

Maybe this is a really stupid question, but I can't figure it out.
Basically all I want to do is emit a single event when the screen is touched (using a physical button on the model of google cardboard that we are ordering). Couldn't work out how to have a 'whole screen touch' so I made a button element outside the a-scene. This is positioned absolutely at the point where the button hits the screen, and console logs when clicked (via mouse) - so I know that the button works. However, trying to emit an event or setAttribute does nothing.
Is there something I'm doing wrong, or is there just some other approach entirely that is better suited?
Here's the code:
<body>
<button id="nav-btn" class="btn btn-primary">Menu</button>
<a-scene id="scene">
and:
AFRAME.registerComponent('nav', {
schema: {},
init: function () {
var navBtn = document.querySelector('#nav-btn');
var btnEls = document.querySelectorAll('.link');
navBtn.addEventListener('click', function () {
console.log('clicked');
for (var i = 0; i < btnEls.length; i++) {
console.log(btnEls[i]);
btnEls[i].emit('menuFade');
}
});
},
});
This works when using an a-entity as a button by the way, but I also couldn't find out how to make that work as a physical button!?
Thanks for any help or advice!
If you care about figuring out when the physical button is pressed on a Google Cardboard, then you don't even need a button element. Attach a "click" or "touchstart" handler to the window and you should be good:
window.addEventListener('touchstart', function(evt) {
console.log('there we go')
})
Note that emit isn't a vanilla JS way of emitting events but an A-Frame specific function, which is why it won't work from a button.
You can use dispatchEvent and CustomEvent for that instead:
window.addEventListener('touchstart', function(evt) {
console.log('there we go')
window.dispatchEvent(new CustomEvent('menuFade'))
})
You may need to change the object that emits the event to something inside the a-scene but it should work.

Stop onclick method running with jQuery

I have a button similar to below
<button id="uniqueId" onclick="runMethod(this)">Submit</button>
What I'm trying to do is stop the runMethod from running, until after I've done a check of my own. I've tried using the stopImmediatePropagation function, but this doesn't seem to have worked. Here's my jQuery:
$j(document).on('click', '#uniqueId', function(event) {
event.stopImmediatePropagation();
if(condition == true) {
// continue...
} else {
return false;
}
return false;
});
Note: runMethod basically validates the form, then triggers a submit.
What you want to do, especially in the way that you want to do it, requires a some sort of workaround that will always be a bit fiddly. It is a better idea to change the way the button behaves (e.g. handle the whole of the click event on the inside of the jQuery click() function or something along those lines). However I have found sort of a solution for your problem, based on the assumption that your user will first hover over the button. I am sure you can extend that functionality to the keyboard's Tab event, but maybe it will not work perfectly for mobile devices' touch input. So, bear in mind the following solution is a semi-complete workaround for your problem:
$(document).ready(function(){
var methodToRun = "runMethod(this)"; // Store the value of the onclick attribute of your button.
var condition = false; // Suppose it is enabled at first.
$('#uniqueId').attr('onclick',null);
$('#uniqueId').hover(function(){
// Check your stuff here
condition = !condition; // This will change to both true and false as your hover in and out of the button.
console.log(condition); // Log the condition's value.
if(condition == true){
$('#uniqueId').attr('onclick',methodToRun); // Enable the button's event before the click.
}
},
function(){
console.log('inactive'); // When you stop hovering over the button, it will log this.
$('#uniqueId').attr('onclick',null); // Disable the on click event.
});
});
What this does is it uses the hover event to trigger your checking logic and when the user finally clicks on the button, the button is enabled if the logic was correct, otherwise it does not do anything. Try it live on this fiddle.
P.S.: Convert $ to $j as necessary to adapt this.
P.S.2: Use the Javascript console to check how the fiddle works as it will not change anything on the page by itself.
Your problem is the submit event, just make :
$('form').on('submit', function(e) {
e.preventDefault();
});
and it works. Don't bind the button click, only the submit form. By this way, you prevent to submit the form and the button needs to be type button:
<button type="button" .....>Submit</button>
Assuming there's a form that is submitted when button is clicked.
Try adding
event.cancelBubble();
Hence your code becomes:
$j(document).on('click', '#uniqueId', function(event) {
// Don't propogate the event to the document
if (event.stopPropagation) {
event.stopPropagation(); // W3C model
} else {
event.cancelBubble = true; // IE model
}
if(condition == true) {
// continue...
} else {
return false;
}
return false;
});
Your code is mostly correct but you need to remove J:
$(document).on('click', '#uniqueId', function(event) {...
You also need to remove the onClick event from the inline code - there's no need to have it there when you're assigning it via jQuery.
<button id="uniqueId">Submit</button>

Link on dropdown Selectize.js

I'm trying to put a link on a selectize dropdown in order to allow the user make an operation other than select an item while still allowing that the user selects the item as main option.
Here is an example of what I want to achieve (but is not working as expected):
What I did is plainly insert links on the HTML. But it's not working, I suppose that for some kind of event propagation stop, is it possible to achieve with selectize?
Nobody did answer yet and I think there's more to say about, so, here is an example of what I did:
render: {
option: function(item) {
return '<div><span>'+item.label+'</span>'
+ '<div class="pull-right">'
+ 'Link'
+ '</div></div>';
}
}
As you can see, I did change the "option" renderization, and inserted a link in plain HTML. The problem is that -as shown on image- when I do click the link, the browser does not follow the link, but executes the default action for selectize, which is selecting the clicked element.
What I want to achieve is to make it follow the link when clicked.
Here is a fiddle of what I did: http://jsfiddle.net/uetpjpa9
The root problem is that Selectize has mousedown and blur handlers that are dismissing the dropdown before the mouseup event that would complete the click that your link is waiting for from ever occurring. Avoiding this without direct support from Selectize is not easy, but it is possible thanks to its plugin system and the amount of access it gives you to Selectize internals.
Here's a plugin that allows a dropdown element with the class clickable to be clicked on. (demo)
Selectize.define('option_click', function(options) {
var self = this;
var setup = self.setup;
this.setup = function() {
setup.apply(self, arguments);
var clicking = false;
// Detect click on a .clickable
self.$dropdown_content.on('mousedown click', function(e) {
if ($(e.target).hasClass('clickable')) {
if (e.type === 'mousedown') {
clicking = true;
self.isFocused = false; // awful hack to defuse the document mousedown listener
} else {
self.isFocused = true;
setTimeout(function() {
clicking = false; // wait until blur has been preempted
});
}
} else { // cleanup in case user right-clicked or dragged off the element
clicking = false;
self.isFocused = true;
}
});
// Intercept default handlers
self.$dropdown.off('mousedown click', '[data-selectable]').on('mousedown click', '[data-selectable]', function() {
if (!clicking) {
return self.onOptionSelect.apply(self, arguments);
}
});
self.$control_input.off('blur').on('blur', function() {
if (!clicking) {
return self.onBlur.apply(self, arguments);
}
});
}
});
To use it, you need to pass the plugin option to the selectize call (.selectize({plugins:['option_click']})) and add the clickable class to links in your dropdown template. (This is fairly specific. If there are nested elements, make sure clickable is on the one that will first see the mousedown event.)
Note that this is a fairly hackish approach that may have edge cases and could break at any time if something about how Selectize dispatches events changes. It would be better if Selectize itself would make this exception, but until the project catches up to its backlog and becomes more receptive to requests and PRs this may be the most practical approach.

Looking for a better workaround to Chrome select on focus bug

I have the same problem as the user in this question, which is due to this bug in Webkit. However, the workaround provided will not work for my app. Let me re-state the problem so that you don't have to go read another question:
I am trying to select all the text in a textarea when it gets focus. The following jQuery code works in IE/FF/Opera:
$('#out').focus(function(){
$('#out').select();
});
However, in Chrome/Safari the text is selected--very briefly--but then the mouseUp event is fired and the text is deselected. The following workaround is offered in the above links:
$('#out').mouseup(function(e){
e.preventDefault();
});
However, this workaround is no good for me. I want to select all text only when the user gives the textarea focus. He must then be able to select only part of the text if he chooses. Can anyone think of a workaround that still meets this requirement?
How about this?
$('#out').focus(function () {
$('#out').select().mouseup(function (e) {
e.preventDefault();
$(this).unbind("mouseup");
});
});
The accepted answer (and basically every other solution I found so far) does not work with keyboard focus, i. e. pressing tab, at least not in my Chromium 21. I use the following snippet instead:
$('#out').focus(function () {
$(this).select().one('mouseup', function (e) {
$(this).off('keyup');
e.preventDefault();
}).one('keyup', function () {
$(this).select().off('mouseup');
});
});
e.preventDefault() in the keyup or focus handler does not help, so the unselecting after a keyboard focus seems to not happen in their default handlers, but rather somewhere between the focus and keyup events.
As suggested by #BarelyFitz, it might be better to work with namespaced events in order to not accidentally unbind other event handlers. Replace 'keyup' with 'keyup.selectText' and 'mouseup' with 'mouseup.selectText' for that.
Why not simply:
$('#out').focus(function(){
$(this).one('mouseup', function() {
$(this).select();
});
});
Seems to work in all major browsers...
A very slightly different approach would be to separate the focus event from the mouse sequence. This works really nicely for me - no state variables, no leaked handlers, no inadvertent removal of handlers, and it works with click, tab, or programmatic focus. Code and jsFiddle below -
$('#out').focus(function() {
$(this).select();
});
$('#out').on('mousedown.selectOnFocus', function() {
if (!($(this).is(':focus'))) {
$(this).focus();
$(this).one('mouseup.selectOnFocus', function(up) {
up.preventDefault();
});
}
});
https://jsfiddle.net/tpankake/eob9eb26/27/
Make a bool. Set it to true after a focus event and reset it after a mouse up event. During the mouse up, if it's true, you know the user just selected the text field; therefore you know you must prevent the mouse up from happening. Otherwise, you must let it pass.
var textFieldGotFocus = false;
$('#out').focus(function()
{
$('#out').select();
textFieldGotFocus = true;
});
$('#out').mouseup(function(e)
{
if (textFieldGotFocus)
e.preventDefault();
});
$(document).mouseup(function() { textFieldGotFocus = false; });
It's important that you put the mouseup listener that resets the variable on document, since it's not guaranteed that the user will release the mouse button over the text field.
onclick="var self = this;setTimeout(function() {self.select();}, 0);"
Select the text before putting the focus on the input box.
$('#out').select().focus();
digitalfresh's solution is mostly there, but has a bug in that if you manually trigger .focus() using JS (so not using a click), or if you tab to the field, then you get an unwanted mouseup event bound - this causes the first click that should deselect the text to be ignored.
To solve:
var out = $('#out');
var mouseCurrentlyDown = false;
out.focus(function () {
out.select();
if (mouseCurrentlyDown) {
out.one('mouseup', function (e) {
e.preventDefault();
});
}
}).mousedown(function() {
mouseCurrentlyDown = true;
});
$('body').mouseup(function() {
mouseCurrentlyDown = false;
});
Note: The mouseup event should be on body and not the input as we want to account for the user mousedown-ing within the input, moving the mouse out of the input, and then mouseup-ing.
tpankake's answer converted to a reusable jQuery function..
(If you upvote this, please also upvote his answer)
Load the following AFTER loading the jQuery library:
$.fn.focusSelect = function () {
return this.each(function () {
var me = $(this);
me.focus(function () {
$(this).select();
});
me.on('mousedown.selectOnFocus', function () {
var me2 = $(this);
if (me2.is(':focus') === false) {
me2.focus();
me2.one('mouseup.selectOnFocus', function (up) {
up.preventDefault();
});
}
});
});
};
Use it like this:
$(document).ready(function () {
// apply to all inputs on the page:
$('input[type=text]').focusSelect();
// apply only to one input
$('#out').focusSelect();
});

Categories