Event listener loop - javascript

How do I add a listener for hovering over div tags like this:
btn1
btn2
btn3
btn4
I want to add a listener that loops through them like I show below and then applies a function if it has mouseover.
function listen() {
for (i=1;i<=10;i++) {
wat = document.getElementById('btn'+i);
wat.addEventListener('mouseover',functionwat,false );
}
}
I have this and its not working, and yes it is calling the function listen(), because I added an alert thing in there to make sure its working correctly, and functionwat works right too. Any idea what I'm doing wrong?

What browser are you using? Registering event handlers is different browser to browser. PPK has some good discussion of browser events here.
In short, this is the cross-browser code for adding a handler.
function addEventSimple(obj,evt,fn) {
if (obj.addEventListener)
obj.addEventListener(evt,fn,false);
else if (obj.attachEvent)
obj.attachEvent('on'+evt,fn);
}
Now you can attach the event with
function listen() {
for (i=1;i<=10;i++) {
wat = document.getElementById('btn'+i);
addEventSimple(wat, 'mouseenter', functionwat);
}
}

Instead of looping for each item and attaching events, look into implementing event delegation. As it relates your situation, let assume you use jQuery and your buttons' markup is as followed:
<div id="btnList">
<button id="btn1">btn1</button>
<button id="btn2">btn2</button>
<button id="btn3">btn3</button>
<button id="btn4">btn4</button>
</div>
JavaScript:
$(document).ready(function()
{
$("#btnList button").bind(
"mouseenter mouseleave",
function(e) {
//do something based on target/id
alert(this.id);
});
});

It seems that you might be somewhat messy with your variables. For instance, you do not use var to declare i, so it might end up in the global namespace. Following this, are you sure functionwat is really a function at the time listen() executes?
You could check that by;
function listen() {
if(typeof functionwat !== "function") {
alert("functionwat is not a function, but a " + typeof functionwat);
}
for (var i = 1; i <= 10; ++i) {
wat = document.getElementById("btn"+i);
wat.addEventListener("mouseover", functionwat, false);
}
}

David,
You're not having any luck because, I am almost positive you are using a browser which is not IE. Your events will not fire in a non-IE browser because the event "mouseenter" is only exposed in IE. To make it work, you need to change "mouseenter" to use "mouseover".
function listen() {
for (i=1;i<=10;i++) {
wat = document.getElementById('btn'+i);
addEventSimple(wat, 'mouseenter', functionwat);
}
}
to
function listen() {
for (i=1;i<=10;i++) {
wat = document.getElementById('btn'+i);
if(wat) { addEventSimple(wat, 'mouseover', functionwat); }
}
}

Related

jQuery events: disable namespaces (or use an event with a period in the name)

I am trying to use .one() to bind to an event with the name similar to something.else.thing, I am not able to change the event name since it comes from an external library.
The problem is because of the periods, jQuery creates namespaces, else and thing for the event something instead of creating an event named something.else.thing.
Is there any way around this?
Thanks
Edit:
Some example code:
$(document).on('appfeel.cordova.admob.onAdLoaded', function() {
console.log('Does nothing');
});
document.addEventListener('appfeel.cordova.admob.onAdLoaded', function() {
console.log('Works');
});
I don't think you can disable jQuery event namespacing so if you want to use one on an event with dots in it you can just do this in pure JS:
Fiddle: http://jsfiddle.net/AtheistP3ace/8z6ewwnv/1/
HTML:
<div id="test"></div>
<button id="mybutton">Run event again</button>
JS:
var test = document.getElementById('test');
var button = document.getElementById('mybutton');
var event = new Event('something.else.blah');
function onWeirdEvent () {
test.removeEventListener('something.else.blah', onWeirdEvent);
alert('did it');
}
test.addEventListener('something.else.blah', onWeirdEvent, false);
test.dispatchEvent(event);
button.addEventListener('click', function (e) {
test.dispatchEvent(event);
}, false);
Its essentially the same thing. If you really want everything to seem jQuery-ish create a custom plugin:
Fiddle: http://jsfiddle.net/AtheistP3ace/8z6ewwnv/2/
$.fn.customOne = function (eventString, fn) {
var self = this[0];
var origFn = fn;
fn = function (event) {
self.removeEventListener(eventString, fn);
return origFn.apply(self);
};
self.addEventListener(eventString, fn, false);
};
$.fn.customTrigger = function (eventString) {
var event = new Event(eventString);
var self = this[0];
self.dispatchEvent(event);
}
$('#test').customOne('something.else.blah', function () {
alert('did it');
});
$('#test').customTrigger('something.else.blah');
$('#test').customTrigger('something.else.blah');
Here is how I decided to go about solving this issue. I went about it this way because this way allows me to continue to use jQuery and all the functionality it provides while keeping my code consistent and only requires a few lines of extra code to go about.
$(document).one('somethingElseThing', function() {
console.log('Event!');
});
document.addEventListener('something.else.thing', function() {
$(document).trigger('somethingElseThing');
});
What I am doing is using straight JavaScript to create an event listener for the event with a period in the name and then I have it trigger a custom event that doesn't a have a period so that I can continue to use jQuery. This I believe is an easy straightforward approach.

Best way to catch mouseup outside of mousedown element

$('#clickableElement').bind({
mousedown: function(e)
{
console.log('mousedown on element');
$(document).bind('mouseup',function(e){
console.log('mouseup caught');
//Do some magic here
$(this).unbind('mouseup');
});
},
mouseup:function(e)
{
//mouseup within element, no use here.
}
});
I'm trying to catch the mouseup event from a mousedown that's released inside or outside of an element. This code almost works, but the problem is the unbind('mouseup') which is unbinding other scripts attached to the mouseup event (jqueryui). If unbind() is not set then the code gets stacked within mouseup event and called x number of times, where x is the times you've mousedowned.
Route 1: is there some kind of self destructing function that calls itself once and destroys?
Route 2: any way to copy/clone the mouseup function prior to inserting the code, then unbind, then set as previous?
Ideally I'd like to keep this code structure for neatness as I have lots of clickable elements, so binding the document.mouseup outside of element.mousedown would be messy.
Here's the Fiddle I forgot to add http://jsfiddle.net/9gFNk/
Can giv your click event a namespace so only that namespaced event gets unbound, and not any others
$(document).on('mouseup.clickableElement',function(e){
console.log('mouseup caught');
//Do some magic here
$(this).off('mouseup.clickableElement');
});
I created a global object to catch mouse events from the document. It's currently set for mouseup only but can be easily expanded for others. The mouseup code is still customizable within the mousedown functions of the clickable elements so it this handy if you have lots of clickable things like I do.
var MouseCatcher=function()
{
this.init=function()
{
var mc = this;
$(document).bind({
mouseup:function(e)
{
mc.mouseup();
}
});
}
this.mouseup=function()
{
return false;
}
}
var mouseCatcher = new MouseCatcher();
mouseCatcher.init();
$('#clickableElement').bind({
mousedown: function(e)
{
console.log('mousedown on element');
mouseCatcher.mouseup=function()
{
console.log('mouseup called from MouseCatcher');
this.mouseup = function(){return false;}
}
},
mouseup:function(e)
{
//mouseup within element, no use here.
}
});
With "on" event its possible, its may not be an exact solution. Please refer this code
$(document).on('mousedown', function() {
$('#clickableElement').css('display', 'none');
$(document).bind('mouseup', function() {
$('#clickableElement').css('display', 'block');
});
});
http://jsfiddle.net/9gFNk/13/

How Store and Disable Event of another element Temporary

I am looking for a way to manage the events. I have a hover function for element A, and click function for element B. I want to disable A`s hover function temporary while the second click of B.
I am looking for a way that not necessary to rewrite the hole function of A inside of B. Something very simply just like "Store and Disable Event, Call Stored Function"
I found some technique like .data('events') and console.log. I tired but failed, or maybe I wrote them in a wrong way.
Please help and advice!
$(A).hover();
$(b).click(
if($.hasData($(A)[0])){ // if A has event,
//STORE all the event A has, and disable
}else{
//ENABLE the stored event for A
}
);
Try this
var hoverme = function() {
alert('Hover Event Fired');
};
$('.A').hover(hoverme);
var i = 0;
$('.B').on('click', function(){
if(i%2 === 0){
// Unbind event
$('.A').off('hover');
}
else{
// Else bind the event
$('.A').hover(hoverme);
}
i++;
});
Check Fiddle
I think that what you want to do is something like this (example for JQuery 1.7.2):
$("#a").hover(function(){alert("test")});
$("#a")[0].active=true;
$("#b").click(function(){
if($("#a")[0].active){
$("#a")[0].storedEvents = [];
var hoverEvents = $("#a").data("events").mouseover;
jQuery.each(hoverEvents , function(key,handlerObj) {
$("#a")[0].storedEvents.push(handlerObj.handler);
});
$("#a").off('hover');
}else{
for(var i=0;i<$("#a")[0].storedEvents.length;i++){
$("#a").hover($("#a")[0].storedEvents[i]);
}
}
$("#a")[0].active = ($("#a")[0].active)==false;
});​
JSFiddle Example
But there are a couple of things that you must have in consideration:
This will only work if you add the events with JQuery, because JQuery keeps an internal track of the event handlers that have been added.
Each version of JQuery handles data("events") differently, that means that this code may not work with other version of JQuery.
I hope that this helps.
EDIT:
data("events") was an internal undocumented data structure used in JQuery 1.6 and JQUery 1.7, but it has been removed in JQuery 1.8. So in JQuery 1.8 the only way to access the events data is through: $._data(element, "events"). But keep in mind the advice from the JQuery documentation: this is not a supported public interface; the actual data structures may change incompatibly from version to version.
You could try having a variable that is outside the scope of functions a and b, and use that variable to trigger the action to take in function b on function a.
var state;
var a = function() {
if(!state) {
state = true;
// Add hover action and other prep. I'd create a third function to handle this.
console.log(state);
};
var b = function() {
if(state) {
state = false;
// Do unbinding of hover code with third function.
} else {
state = true;
// Do whatever else you needed to do
}
}
Without knowing more about what you're trying to do, I'd try something similar to this.
It sounds like you want to disable the click hover event for A if B is clicked.
$("body").on("hover", "#a", function(){
alert("hovering");
});
$("#b").click( function(){
$("body").off("hover", "#a", function() {
alert("removed hovering");
});
});
You can use the jQuery off method, have a look at this fiddle. http://jsfiddle.net/nKLwK/1/
Define a function to assign to hover on A element, so in b click, call unbind('hover') for A element and in second click on b element define again a function to hover, like this:
function aHover(eventObject) {
// Todo when the mouse enter object. You can use $(this) here
}
function aHoverOut(eventObject) {
// Todo when the mouse leave the object. You can use $(this) here
}
$(A).hover(aHover, aHoverOut);
// ...
$(b).click(function(eventObject) {
if($.hasData($(A)[0])){ // if A has event,
$(A).unbind('mouseenter mouseleave'); // This is because not a event hover, jQuery convert the element.hover(hoverIn, hoverOut) in element.bind('mouseenter', hoverIn) and element.bind('mouseleave', hoverOut)
}else{
$(A).hover(aHover, aHoverOut);
}
});
There are provably better ways to do it, but this works fine, on document ready do this:
$("#a")[0].active=false;
$("#b").click(function(){
$("#a")[0].active = ($("#a")[0].active)==false;
if($("#a")[0].active){
$("#a").hover(function(){alert("test")});
}else{
$("#a").off('hover');
}
});
JSFiddle example
You can use .off function from jQuery to unbind the hover on your "a" element.
function hoverA() {
alert('I\'m on hover');
}
$('#a').hover( hoverA );
var active = true;
$('#b').on('click', function(){
if(active){
$('#a').off('hover');
active = false;
} else{
$('#a').hover(hoverA);
active = true;
}
});
Live demo available here : http://codepen.io/joe/pen/wblpC

Binding a function that is already bound to another element

I have a bunch of elements that get three different classes: neutral, markedV and markedX. When a user clicks one of these elements, the classes toggle once: neutral -> markedV -> markedX -> neutral. Every click will switch the class and execute a function.
$(document).ready(function(){
$(".neutral").click(function markV(event) {
alert("Good!");
$(this).addClass("markedV").removeClass("neutral");
$(this).unbind("click");
$(this).click(markX(event));
});
$(".markedV").click(function markX(event) {
alert("Bad!");
$(this).addClass("markedX").removeClass("markedV");
$(this).unbind("click");
$(this).click(neutral(event));
});
$(".markedX").click(function neutral(event) {
alert("Ok!");
$(this).addClass("neutral").removeClass("markedX");
$(this).unbind("click");
$(this).click(markV(event));
});
});
But obviously this doesn't work. I think I have three obstacles:
How to properly bind the changing element to the already defined function, sometimes before it's actually defined?
How to make sure to pass the event to the newly bound function [I guess it's NOT accomplished by sending 'event' to the function like in markX(event)]
The whole thing looks repetitive, the only thing that's changing is the alert action (Though each function will act differently, not necessarily alert). Is there a more elegant solution to this?
There's no need to constantly bind and unbind the event handler.
You should have one handler for all these options:
$(document).ready(function() {
var classes = ['neutral', 'markedV', 'markedX'],
methods = {
neutral: function (e) { alert('Good!') },
markedV: function (e) { alert('Bad!') },
markedX: function (e) { alert('Ok!') },
};
$( '.' + classes.join(',.') ).click(function (e) {
var $this = $(this);
$.each(classes, function (i, v) {
if ( $this.hasClass(v) ) {
methods[v].call(this, e);
$this.removeClass(v).addClass( classes[i + 1] || classes[0] );
return false;
}
});
});
});
Here's the fiddle: http://jsfiddle.net/m3CyX/
For such cases you need to attach the event to a higher parent and Delegate the event .
Remember that events are attached to the Elements and not to the classes.
Try this approach
$(document).ready(function () {
$(document).on('click', function (e) {
var $target = e.target;
if ($target.hasClass('markedV')) {
alert("Good!");
$target.addClass("markedV").removeClass("neutral");
} else if ($target.hasClass('markedV')) {
alert("Bad!");
$target.addClass("markedX").removeClass("markedV");
} else if ($target.hasClass('markedX')) {
alert("Ok!");
$target.addClass("neutral").removeClass("markedX");
}
});
});
OR as #Bergi Suggested
$(document).ready(function () {
$(document).on('click', 'markedV',function (e) {
alert("Good!");
$(this).addClass("markedV").removeClass("neutral");
});
$(document).on('click', 'markedX',function (e) {
alert("Bad!");
$(this).addClass("markedX").removeClass("markedV");
});
$(document).on('click', 'neutral',function (e) {
alert("Ok!");
$(this).addClass("neutral").removeClass("markedX");
});
});
Here document can be replaced with any static parent container..
How to properly bind the changing element to the already defined function, sometimes before it's actually defined?
You don't bind elements to functions, you bind handler functions to events on elements. You can't use a function before it is defined (yet you might use a function above the location in the code where it was declared - called "hoisting").
How to make sure to pass the event to the newly bound function [I guess it's NOT accomplished by sending 'event' to the function like in markX(event)]
That is what happens implicitly when the handler is called. You only need to pass the function - do not call it! Yet your problem is that you cannot access the named function expressions from outside.
The whole thing looks repetitive, the only thing that's changing is the alert action (Though each function will act differently, not necessarily alert). Is there a more elegant solution to this?
Yes. Use only one handler, and decide dynamically what to do in the current state. Do not steadily bind and unbind handlers. Or use event delegation.

How to write onshow event using JavaScript/jQuery?

I have an anchor tag on my page, I want an event attached to it, which will fire when the display of this element change.
How can I write this event, and catch whenever the display of this element changes?
This is my way of doing on onShow, as a jQuery plugin. It may or may not perform exactly what you are doing, however.
(function($){
$.fn.extend({
onShow: function(callback, unbind){
return this.each(function(){
var _this = this;
var bindopt = (unbind==undefined)?true:unbind;
if($.isFunction(callback)){
if($(_this).is(':hidden')){
var checkVis = function(){
if($(_this).is(':visible')){
callback.call(_this);
if(bindopt){
$('body').unbind('click keyup keydown', checkVis);
}
}
}
$('body').bind('click keyup keydown', checkVis);
}
else{
callback.call(_this);
}
}
});
}
});
})(jQuery);
You can call this inside the $(document).ready() function and use a callback to fire when the element is shown, as so.
$(document).ready(function(){
$('#myelement').onShow(function(){
alert('this element is now shown');
});
});
It works by binding a click, keyup, and keydown event to the body to check if the element is shown, because these events are most likely to cause an element to be shown and are very frequently performed by the user. This may not be extremely elegant but gets the job done. Also, once the element is shown, these events are unbinded from the body as to not keep firing and slowing down performance.
You can't get an onshow event directly in JavaScript. Do remember that the following methods are non-standard.
IN IE you can use
onpropertychange event
Fires after the property of an element
changes
and for Mozilla
you can use
watch
Watches for a property to be assigned
a value and runs a function when that
occurs.
You could also override jQuery's default show method:
var orgShow = $.fn.show;
$.fn.show = function()
{
$(this).trigger( 'myOnShowEvent' );
orgShow.apply( this, arguments );
return this;
}
Now just bind your code to the event:
$('#foo').bind( "myOnShowEvent", function()
{
console.log( "SHOWN!" )
});
The code from this link worked for me: http://viralpatel.net/blogs/jquery-trigger-custom-event-show-hide-element/
(function ($) {
$.each(['show', 'hide'], function (i, ev) {
var el = $.fn[ev];
$.fn[ev] = function () {
this.trigger(ev);
return el.apply(this, arguments);
};
});
})(jQuery);
$('#foo').on('show', function() {
console.log('#foo is now visible');
});
$('#foo').on('hide', function() {
console.log('#foo is hidden');
});
However the callback function gets called first and then the element is shown/hidden. So if you have some operation related to the same selector and it needs to be done after being shown or hidden, the temporary fix is to add a timeout for few milliseconds.

Categories