Multiple classes with onmouseenter/leave event? - javascript

I have multiple items with the same class I want to change when the user hovers over them.
I could add the events like this in the HTML but this seems rather unpretty:
<div class="video-item" onmouseenter="overVideoStart(this)"></div>
The JavaScript looks like this:
function overVideoStart(element)
{
element.className += " video-item-hover";
...
}
Is there a more good looking way to do this? I wish to leave the onmouseenter attribute away and instead have it defined in the JavaScript file. There is a way to do this for single items but I haven't found a way to do this for classes. I'm sorry if this is a total noob question but this is my first time I'm working with JavaScript.

You can use addEventListener to add events to elements in JS.
To add event listeners to multiple elements you would need to capture all the elements first and loop through them and set each one to have a listener.
var elements = document.querySelectorAll('.video-item');
for(var i=0; i<elements.length; i++){
elements[i].addEventListener("mouseenter",mouseEnter);
}
function mouseEnter(e){
//e will refer to the event object
//you can refer to the element with keyword "this"
}
If you include a library like jQuery you can shorten the code a little as it will do the looping and other work behind the scenes
jQuery('.video-item').mouseenter(mouseEnter);
function mouseEnter(e){
//e will refer to the event object
//you can refer to the element with keyword "this"
}

You can add jQuery to your webpage, and use it's css selector like queries to set at once callbacks for elements that match the query.
For example in your case:
jQuery(".video-item").mouseenter(function(event) {
// handle the mouse enter
});
Or, if the matching elements can change over time - e.g. via ajax calls - you can use the more powerful .on() function.

Related

Subscribe to click events from checkboxes that share a CSS class, no jQuery?

I believe in jQuery the way to do what I'm looking for is
$('.checkbox-class').click(handler);
Is it possible to do this without jQuery?
Is it possible to do this without jQuery?
jQuery is written in JavaScript, so it's always possible to write jQuery code in terms of plain JS.
There are two things happening in that jQuery statement:
Select all elements with class checkbox-class
Attach a callback function to be called when any of the elements are clicked
Selecting elements in JavaScript can be done with the querySelectorAll method. For example:
const checkboxes = document.querySelectorAll('.checkbox-class');
Note that this returns an Array-like object with each matching element.
To add an event listener to an element, we use addEventListener. For example:
e.addEventListener('click', handler);
To put the two together, we need to iterate over each checkbox element and add the click handler.
const checkboxes = document.querySelectorAll('.checkbox-class');
Array.from(checkboxes).forEach(e => e.addEventListener('click', handler));
Array.from allows us to use methods from the Array prototype on the Array-like collection of elements returned by querySelector[All]. The forEach method iterates over each element and the inner function (using fat-arrow syntax) does the event binding.
CodePen example.
First, get all the elements with the same class name with the getElementsByClassName method. Then use use a for loop and apply to each element the addEventListener method to add the click event.
var checkboxes = document.getElementsByClassName('checkbox-class');
for (i = 0; i < checkboxes.length; i++) {
checkboxes[i].addEventListener('click', function() {
console.log('checkbox checked');
})
};
Modern browsers now support querySelector which does what jQuery does, see this page for details.
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
Also you can use addEventListener to get events. See this page
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Event_handlers

Find one DOM node when several share the same class

I am stuck at one place in jquery, In have multiple dropdowns which is generating dynamically and have the same class name.
I am trying to trigger a click event on that class but that is affecting all of them.
What i want is just to point to the one which comes in a loop not to all
Something like this. ?
here is the jquery
if(olddate[0]==='')
{
$(".month").first().val($(".month option:first").first().trigger("change"));
}
if(olddate[1]==='')
{
$(".day").val($(".day option:first").trigger("change"));
}
if(olddate[2]==='')
{
$(".year").val($(".year option:first").trigger("change"));
}
To make the code work, you have to create "context" somehow. Context can be:
Wrap each dropdowns in an element has an ID. You can then do $('#id .month') to locate the node. See Descendant Selector
Save the root of the dropdown in a JavaScript variable. You can then do $('.class', rootNode) to locate it. See jQuery()

Jquery Class Selector Fails to Select new Class Instances Added with .append()

I'm semi-new to Javascript/jQuery so apologies in advanced if I'm missing something basic. I have a function that is triggered whenever a user types in an element with a specific class.
$('.relevantClass').keyup(function(){
//code...
});
Now this function may end up, depending on the situation, creating a good deal of new HTML including new instances of relevantClass through the .append() method.
var newHTML = <div class='relevantclass'>Content...</div>;
$('#wrapper').append(newHtml);
However, the jQuery selector does not seem to detect and execute the function when a user types in the newly created relevantClasses. I've checked the newly created Html and it has the correct class tags and old instances of the relevant class due work.
I'm guessing this has something to do with .append(); messing with the DOM and I need someway to "refresh" the selector and let it do its jQuery thing researching the DOM to find the new classes. Any thoughts on how to do this? Is there some jQuery method I can't find?
You have to use on() to attach events that work on dynamic content:
var $parent = $("selector"); //the element you're appending .relevantClass to
$parent.on("keyup",".relevantClass",function(){
//code...
});
Keep in mind that to work with dynamic content, you have to attach the event to relevantClass's closest parent that exists on page load.
Some people use body, but you should get used to using parent elements as close as you can get to the dynamic content. This is so that event delegation occurs on a smaller scale.
More info on on() here.
Also, I hope that newhtml variable is wrapped in quotes.
$('.relevantClass').on('keyup', function(){
//code...
});
Try something like
$('body').on('keyup', '.relevantClass', function() { ... }
The idea is that you use an existing root element and use your class selector as a filter. See the examples here.

jQuery on() method - which way to use is better for performance?

Is it better to attach the on() event to the document or a closer parent?
Note: Initially this question had another aspect and a different topic. It became obsolete really quickly (typo in the source code)
The best key for performance using jQuery is to use an id as the initial identifier. For example:
$('#my_id').on('click', 'tag.my_class', function () {
...
});
This allows jQuery to go straight to the container, and then begin trawling from there.
if you bind the "on" event to the closest parent will produce exactly what are you looking for, click function will works fine even if it is appended to document, but in future if you append any elements with class "clickable" will also get binded. so its always good practice to append the "on" event to closest parent rather than whole document.
if you want more specific you can use
$("ul.media-grid").on('click', 'li.clickable', function () {
alert("works")
});
as it will get the ul with the class "media-grid" and appends the event to the li's with class "clickable"

Simple Horizontal Javascript Navigation with Prototype

I'm trying to implement a simple horizontal navigation menu that just shows a single div for each link. It is kinda like a dropdown menu but instead of a mouseover triggering a dropdown, an onclick event will trigger the showing of a div. I want to make sure I am taking the right approach before going too much further, any help is appreciated. This is what I have so far:
<ul id="settings_nav">
<li>
<a>Theme</a>
<div id="settings_block"><%= render :partial => 'email_password' %></div>
</li>
<li>
Lists
<div id="settings_block"><%= render :partial => 'lists' %></div>
</li>
</ul>
window.onload = function(){
settingsMenuInit('settings_nav')
}
function settingsMenuInit(settings_nav){
$(settings_nav).childElements().each(
function(node){
node.onclick= function(){ this.next.show() };
})
}
Something like that, but I am unsure how to get the div that is currently shown and hide it. I could iterate through all the childElements and hide each div and then show the one that is being clicked, but maybe there's a better way?
Some notes FW(T)W:
With Prototype and similar libraries, you don't want to hook up event handlers by assigning functions to the element's onclick and similar properties; that style has several disadvantages (not least that there can only be one handler for the event on the element). Instead, use Prototype's observe function:
someElement.observe('click', functionRefHere);
// or
Element.observe(someElementOrID, 'click', functionRefHere);
This also lets Prototype work around some IE memory loss bugs for you.
You might look at is Prototype's dom:loaded event, which happens sooner than window.onload (which won't happen until all of your images and other external resources have loaded, which can be a second or two after the page is displayed):
document.observe('dom:loaded', initFunctionRefHere);
You can use event delegation and just watch your settings_nav element, rather than each child node individually.
$(settings_nav).observe('click', handleNavClick);
function handleNavClick(event) {
var elm = event.findElement("some CSS selector here");
if (elm) {
event.stop();
// Handle it
}
}
As you can see, Event#findElement accepts a CSS selector. It starts with the actual element that was clicked and tries to match that with the selector; if it matches, it returns the element, otherwise it goes to the parent to see if it matches; etc. So with your HTML you might look for a li (event.findElement('li')) or the link (event.findElement('a')).
But if you want to watch each one individually, they can share a function (as they do in your example):
$(settings_nav).childElements().invoke('observe', 'click', handleNavClick);
function handleNavClick(event) {
// Prototype makes `this` reference the element being observed, so
// `this` will be the `li` element in this example.
}
Whether you watch each element individually or use event delegation depends on what you're doing (and personal preference). Whenever anything is likely to change (adding and removing navigation li elements, for instance) or when there are lots of things to watch, look to event delegation -- it's much easier simpler to deal with changing sets of elements using event delegation and just watching the parent. When dealing with a stable structure of just a few things (as in your example), it may be simpler to just watch the elements individually.
Once inside your handler, you can use Element#down to find child elements (so from the li, you might use li.down('div') to find the div), or Element#next to get to the next sibling element (e.g., going from the link to the div). Either way, once you have a reference to the div, you can use Element#show and Element#hide (or Element#toggle).
I recommend using named functions instead of anonymous ones (see my example above). Named functions help your tools (debuggers, browsers showing errors, etc.) help you. Just be sure not to declare a named function and use it as an expression (e.g., don't immediately assign it to something):
// Don't do this because of browser implementation bugs:
someElement.observe('click', function elementClickHandler(event) {
// ...
});
// Do this instead:
someElement.observe('click', elementClickHandler);
function elementClickHandler(event) {
// ...
}
...because although you should be able to do that according to the spec, in reality various bugs in various browsers make it not work reliably (article).

Categories

Resources