Trigger onmouseover event programmatically in JavaScript - javascript

Is there a way to programmatically trigger the onmouseover event in plain JavaScript? or "extract" the method from the onmouseover event to call it directly?
eg
<div id="bottom-div" onmouseover="myFunction('some param specific to bottom-div');">
<div id="top-div" onmouseover="????????"></div>
</div>
top-div is above bottom-div, so the onmouseover won't get fired in bottom-div. i need a way of calling myFunction('some param specific to bottom-div'); from top-div

const mouseoverEvent = new Event('mouseover');
whateverElement.dispatchEvent(mouseoverEvent);

This worked for me in IE9 at least. Should be cross-browser compatible or close to it...
function FireEvent( ElementId, EventName )
{
if( document.getElementById(ElementId) != null )
{
if( document.getElementById( ElementId ).fireEvent )
{
document.getElementById( ElementId ).fireEvent( 'on' + EventName );
}
else
{
var evObj = document.createEvent( 'Events' );
evObj.initEvent( EventName, true, false );
document.getElementById( ElementId ).dispatchEvent( evObj );
}
}
}
For onmouseover example, call the function like this
FireEvent( ElementId, "mouseover" );

For me following worked:
​document.getElementById('xyz').dispatchEvent(new MouseEvent('mouseover', { 'bubbles': true }));
Also:
​document.getElementById('xyz').dispatchEvent(new MouseEvent('mouseover', { 'view': window, 'bubbles': true, 'cancelable': true }));

Without going into too much detail, I had an img with rollovers, i.e. mouseout/overs that set the img src to hidden form values (or this could have done in a different context with gloabl variables). I used some javascript to swap both of my over/out image values and I called the called FireEvent( ElementId, "mouseover" ); to trigger the change. My javascript was hiding / displaying elements on the page. This caused the cursor to sometimes be over the img I used to trigger the event - which was the same as the one I was swapping out, and sometimes the cursor was not over the img after the click.
Mouseover/out does not fire unless you exit and re-enter an element, so after my event was triggered the mouseover/out needed "retriggering" to account for the new cursor position. Here is my solution. After I hide / display various page elements, and to do my img src swapping as described, I call the function RefreshMouseEvents( ElementId ) instead of FireEvent( ElementId, "mouseover" ).
This works in IE9 (not sure about other browsers).
function RefreshMouseEvents( ElementId )
{
FireEvent( ElementId, 'mouseover' );
setTimeout( "TriggerMouseEvent( '" + ElementId + "' )" , 1 );
}
function TriggerMouseEvent( ElementId )
{
if( IsMouseOver( ElementId, event.clientX, event.clientY ) )
FireEvent( ElementId, 'mouseover' );
else
FireEvent( ElementId, 'mouseout' );
}
function IsMouseOver( ElementId, MouseXPos, MouseYPos )
{
if( document.getElementById(ElementId) != null )
{
var Element = document.getElementById(ElementId);
var Left = Element.getBoundingClientRect().left,
Top = Element.getBoundingClientRect().top,
Right = Element.getBoundingClientRect().right,
Bottom = Element.getBoundingClientRect().bottom;
return ( (MouseXPos >= Left) && (MouseXPos <= Right) && (MouseYPos >= Top) && (MouseYPos <= Bottom))
}
else
return false;
}
function FireEvent( ElementId, EventName )
{
if( document.getElementById(ElementId) != null )
{
if( document.getElementById( ElementId ).fireEvent )
{
document.getElementById( ElementId ).fireEvent( 'on' + EventName );
}
else
{
var evObj = document.createEvent( 'Events' );
evObj.initEvent( EventName, true, false );
document.getElementById( ElementId ).dispatchEvent( evObj );
}
}
}

I had to revise my RefreshMouseEvents set of functions after more testing. Here is the seemingly perfected version (again only IE9 tested):
function RefreshMouseEvents( ElementId )
{
FireEvent( ElementId, 'mouseover' );
setTimeout( "TriggerMouseEvent( '" + ElementId + "', '" + event.clientX + "', '" + event.clientY + "' )", 1 );
}
function TriggerMouseEvent( ElementId, MouseXPos, MouseYPos )
{
if( IsMouseOver( ElementId, (1*MouseXPos), (1*MouseYPos) ) )
FireEvent( ElementId, 'mouseover' );
else
FireEvent( ElementId, 'mouseout' );
}
function IsMouseOver( ElementId, MouseXPos, MouseYPos )
{
if( document.getElementById(ElementId) != null )
{
var Element = document.getElementById(ElementId);
var Left = Element.getBoundingClientRect().left,
Top = Element.getBoundingClientRect().top,
Right = Element.getBoundingClientRect().right,
Bottom = Element.getBoundingClientRect().bottom;
return ( (MouseXPos >= Left) && (MouseXPos <= Right) && (MouseYPos >= Top) && (MouseYPos <= Bottom))
}
else
return false;
}
function FireEvent( ElementId, EventName )
{
if( document.getElementById(ElementId) != null )
{
if( document.getElementById( ElementId ).fireEvent )
{
document.getElementById( ElementId ).fireEvent( 'on' + EventName );
}
else
{
var evObj = document.createEvent( 'Events' );
evObj.initEvent( EventName, true, false );
document.getElementById( ElementId ).dispatchEvent( evObj );
}
}
}

I needed to do something similar, but I'm using jQuery, and I found this to be a better solution:
Use jQuery's trigger function.
$j('#top-div' ).trigger( 'mouseenter' );
You can also add parameters to it if you need to. See the jQuery documentation on .trigger.

​<a href="index.html" onmouseover="javascript:alert(0);" id="help"​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​>help</a>​​​​​​​​​​​​​​​​​​​​​​​​​​​
​document.getElementById('help').onmouseover();​​​​​​​

I was working with Angular and trying to do a similar thing.
I fall on this answer from StackOverflow Click here
Basically the idea is to add and remove the hover class
public addHoverOnClick() {
const yourElement = document.getElementById('elementID') as HTMLElement;
yourElement .classList.add('hover')
}
public removeHoverOnClick() {
const yourElement = document.getElementById('elementID') as HTMLElement;
yourElement .classList.remove('hover')
}

You would do it something like this:
document.getElementById('top-div').onmouseover();
However, as mentioned in the comments, it would be worth testing before being considered an issue.

Related

How can I use this multiselect dropdown twice on one page so each instance outputs to its own array?

I want to place two separate multiselct dropdown menus on one page for a form I am designing.
I found this lovely dropdown with checkboxes that I would like to use:
https://codepen.io/bseth99/pen/fboKH
I am trying to figure out the best way to run two instances of this dropdown on the same page, so that each dropdown's selections are saved in their own array.
var options = [];
$( '.dropdown-menu a' ).on( 'click', function( event ) {
var $target = $( event.currentTarget ),
val = $target.attr( 'data-value' ),
$inp = $target.find( 'input' ),
idx;
if ( ( idx = options.indexOf( val ) ) > -1 ) {
options.splice( idx, 1 );
setTimeout( function() { $inp.prop( 'checked', false ) }, 0);
} else {
options.push( val );
setTimeout( function() { $inp.prop( 'checked', true ) }, 0);
}
$( event.target ).blur();
console.log( options );
return false;
});
Right now, if I place two instances of the button's HTML on my page, both dropdowns will modify the same "options" array because it's using a class selector for dropdown-menu. I know I can use an ID selector instead of a class selector, and then just use the same block of jQuery over again with a different array, but is that really the best way to do this? I am new to jQuery but that seems bloated.
$( '.dropdown-menu a' ).on( 'click', function( event ) {
var $target = $( this ),
val = $target.data( 'value' ),
$inp = $target.find( 'input' ),
idx;
var options = $target.closest('.dropdown-menu').data('options') || [];
if ( ( idx = options.indexOf( val ) ) > -1 ) {
options.splice( idx, 1 );
setTimeout( function() { $inp.prop( 'checked', false ) }, 0);
} else {
options.push( val );
setTimeout( function() { $inp.prop( 'checked', true ) }, 0);
}
$target.closest('.dropdown-menu').data('options', options);
$( event.target ).blur();
return false;
});
console.log($( '.dropdown-menu:eq(0)' ).data('options'));

jquery single slide handle

I have a HTML page with an ordinary jquery slider from jquery 1.12.1
But the slider has 2 handles and I can't manage to find the line of code that generates two handles. I've deleted the "values [x,y]" part in the script on my html, but it still gives two handles.
I think this is the JavaScript that generates it, but I'm not familiar with JS, so
_createHandles: function() {
var i, handleCount,
options = this.options,
existingHandles = this.element.find( ".ui-slider-handle" ),
handle = "<span tabindex='0'></span>",
handles = [];
handleCount = ( options.values && options.values.length ) || 1;
if ( existingHandles.length > handleCount ) {
existingHandles.slice( handleCount ).remove();
existingHandles = existingHandles.slice( 0, handleCount );
}
for ( i = existingHandles.length; i < handleCount; i++ ) {
handles.push( handle );
}
this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
this._addClass( this.handles, "ui-slider-handle", "ui-state-default" );
this.handle = this.handles.eq( 0 );
this.handles.each( function( i ) {
$( this )
.data( "ui-slider-handle-index", i )
.attr( "tabIndex", 0 );
} );
I think this is the piece that does something, but I can't understand it's variables; where they come from.
for ( i = existingHandles.length; i < handleCount; i++ ) {
handles.push( handle );
}
If somebody knows how to delete this piece of code whilst making the handle appear afterwards (I tried to delete different lines, but that didn't work), Thank you very much in advance!
That is a for loop that I believe creates a handle as long as i is less than the variable handleCount. You will need to change the variable handleCount so that the for loop only executes once, thus creating one handle.
something like:
handleCount = 1;
You just need to remove the range: true option.
When this is removed, you are left with a slider with only 1 handle.
range: If set to true, the slider will detect if you have two handles
and create a styleable range element between these two.
http://api.jqueryui.com/slider/#option-range
Also, if you only want one handle, you should probably just use the value property, instead of values.
http://api.jqueryui.com/slider/#option-value
$(function(){
//creates 2 handles
$( ".example-a" ).slider({
range: true,
values: [0]
});
//creates 1 handle slider
$( ".example-b" ).slider({
values: [0]
});
//also creates 1 handle slider
$( ".example-c" ).slider({
value: 0
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.0/jquery-ui.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<h2>Example A - 2 handles<h2>
<div class="example-a"></div>
<h2>Example B - 1 handle (values)<h2>
<div class="example-b"></div>
<h2>Example C - 1 handle (value)<h2>
<div class="example-c"></div>
Okay, so that's fixed, but one thing remains and that is that JS now searches for the other handle to create a colour in the spacing between the two.
if ( !this.range || !this.range.length ) {
this.range = $( "<div>" )
.appendTo( this.element );
this._addClass( this.range, "ui-slider-range" );
} else {
this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" );
// Handle range switching from true to min/max
this.range.css( {
"left": "",
"bottom": ""
} );
}
if ( options.range === "min" || options.range === "max" ) {
this._addClass( this.range, "ui-slider-range-" + options.range );
}
} else {
if ( this.range ) {
this.range.remove();
}
this.range = null;
}
},
Maybe this is something I have to rewrite. I don't know.
// Handle range switching from true to min/max
this.range.css( {
"left": "",
"bottom": ""

JavaScript on input event

I have a form with CSS animations, when form field is selected labels animate out and when text is filled labels shouldn't animate back. And this works for input fields but not with textarea. Can't seem to find the problem, and I've been playing with it for some time now.
This is my JS code:
<script>
(function() {
// trim polyfill : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim
if (!String.prototype.trim) {
(function() {
// Make sure we trim BOM and NBSP
var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
String.prototype.trim = function() {
return this.replace(rtrim, '');
};
})();
}
[].slice.call( document.querySelectorAll('input.input_field', 'input-textarea.input_field-textarea') ).forEach( function( inputEl ) {
// in case the input is already filled..
if( inputEl.value.trim() !== '' ) {
classie.add( inputEl.parentNode, 'input--filled' );
}
// events:
inputEl.addEventListener( 'focus', onInputFocus );
inputEl.addEventListener( 'blur', onInputBlur );
} );
function onInputFocus( ev ) {
classie.add( ev.target.parentNode, 'input--filled' );
}
function onInputBlur( ev ) {
if( ev.target.value.trim() === '' ) {
classie.remove( ev.target.parentNode, 'input--filled' );
}
}
})();
</script>
EDIT: This was the problem, code was going like this:
document.querySelectorAll('textarea.input_field-textarea', 'input.input_field'))
Instead of removing those 2 extra '':
document.querySelectorAll('textarea.input_field-textarea, input.input_field'))
Thanks to all for help!
Change the input-textarea.input_field-textarea selector to textarea.input_field-textarea. There's no such <input-textarea/> element:
[].slice.call(document.querySelectorAll('input.input_field', 'textarea.input_field-textarea')).forEach(function(inputEl) {
// ...
});

jQuery confliction with the menu

I'm working a site which is having a jQuery conflicting error. I tried few practices from the internet but I always failed. Please take a look at the script and teach me how I can solve this error.
/**
* navigation.js
*
* Handles toggling the navigation menu for small screens.
*/
( function() {
var container = document.getElementById( 'site-navigation' ),
button = container.getElementsByTagName( 'h1' )[0],
menu = container.getElementsByTagName( 'ul' )[0];
if ( undefined == button || undefined == menu )
return false;
button.onclick = function() {
if ( -1 == menu.className.indexOf( 'nav-menu' ) )
menu.className = 'nav-menu';
if ( -1 != button.className.indexOf( 'toggled-on' ) ) {
button.className = button.className.replace( ' toggled-on', '' );
menu.className = menu.className.replace( ' toggled-on', '' );
container.className = container.className.replace( 'main-small-navigation', 'navigation-main' );
} else {
button.className += ' toggled-on';
menu.className += ' toggled-on';
container.className = container.className.replace( 'navigation-main', 'main-small-navigation' );
}
};
// Hide menu toggle button if menu is empty.
if ( ! menu.childNodes.length )
button.style.display = 'none';
} )();
Thanks :)
You need to add "jQuery" on the end:
jQuery.noConflict();
(function( $ ) {
// Your jQuery code here, using the $
})( jQuery );
Taken from: http://learn.jquery.com/using-jquery-core/avoid-conflicts-other-libraries/
Try this.
$j = jQuery.noConflict();
Now use $j wherever jQuery is needed to be used.
e.g. use jQuery code j$(...) wherever jQuery is needed.

Onmouseover child div problem and event bubbling

I have a small div above (hover) a big one.
I assign onmouseover and onmouseout events to the wrapper div.
For image caption roll-over animation.
The problem is when the mouse is above the caption itself, causing an unwanted result (probably event bubbling).
And another problem: sometimes when you move mouse from outside to container you get a a triple sequence: (it should be just 2):
-I am over-
-I am out-
-I am over-
How to make it work? (no jQuery)
Must work on all browsers.
Demo
I have added firebug console log, to a better debugging.
UPDATE:
I've added this (not in the online demo) in RollOverDescription:
if (!eventHandle) var eventHandle = window.event;
var srcEle = eventHandle.srcElement.id;
if(srcEle=="imageDescription" ){
return;
}
But it doesn't help.
This article on quirksmode ( near the bottom ) has an explanation of what you are experiencing and a script that might help you. There is a lot of cross browser info regarding mouse events too
OK, here's some working code. I don't promise this is the most efficient or that it won't cause memory leaks in IE (or that it works in IE - please let me know ). This is why people use libraries, much safer and easier.
// a general purpose, cross browser event adder
// returns a function that if run removes the event
function addEvent( el, eventType, handler, capturing ) {
if( el.addEventListener ) {
el.addEventListener( eventType, handler, capturing || false );
var removeEvent = function() { el.removeEventListener( eventType, handler, capturing || false ) };
} else if( el.attachEvent ) {
var fn = function() {
handler.call( el, normalise( window.event ) );
};
el.attachEvent( 'on'+eventType, fn );
var removeEvent = function(){ el.detachEvent( 'on'+eventType, fn ) };
}
function normalise( e ) {
e.target = e.srcElement;
e.relatedTarget = e.toElement;
e.preventDefault = function(){ e.returnValue = false };
e.stopPropagation = function(){ e.cancelBubble = true };
return e;
};
return removeEvent;
};
// adds mouseover and mouseout event handlers to a dom element
// mouseover and out events on child elements are ignored by this element
// returns a function that when run removes the events
// you need to send in both handlers - an empty function will do
function addMouseOverOutEvents( element, overHandler, outHandler ) {
function out( e ) {
var fromEl = e.target;
var toEl = e.relatedTarget;
// if the mouseout didn't originate at our element we can ignore it
if( fromEl != element ) return;
// if the element we rolled onto is a child of our element we can ignore it
while( toEl ) {
toEl = toEl.parentNode;
if( toEl == element ) return;
}
outHandler.call( element, e );
}
function over( e ) {
var toEl = e.target;
var fromEl = e.relatedTarget;
// if the mouseover didn't originate at our element we can ignore it
if( toEl != element ) return;
// if the element we rolled from is a child of our element we can ignore it
while( fromEl ) {
fromEl = fromEl.parentNode;
if( fromEl == element ) return;
}
overHandler.call( element, e );
}
var killers = [];
killers.push( addEvent( element, 'mouseover', over ) );
killers.push( addEvent( element, 'mouseout', out ) );
return function() {
killers[0]();
killers[1]();
}
}
Example of use:
// add the events
var remover = addMouseOverOutEvents(
document.getElementById( 'elementId' ),
function( e ) {
this.style.background = 'red';
console.log( 'rolled in: '+e.target.id );
},
function( e ) {
this.style.background = 'blue'
console.log( 'rolled out: '+e.target.id );
}
);
//remove the events
remover();

Categories

Resources