How can I apply something to all elements now and in the future which have a title attribute set?
The reason why I want to achieve this is simple:
I have a footer in a webapp where, like many apps, I'd like to have some information written on hovering some elements.
I'd like to set this information in the title attribute of the elements I want to display information for.
So every element with a title should trigger a function on hover. Even elements that are added dynamically.
I found this to have something work on mouse enter+leave that is suposed to work for added elements:
$(document).on(
{
mouseenter: function()
{
//stuff to do on mouseover
},
mouseleave: function()
{
//stuff to do on mouseleave
}
}
, "*[special-selector]");
what's the special selector supposed to be?
Secondary question: How can I acces the $(this).attr('title') attribute from within the scope of these 2 anonymous functions?
Any Idea? or maybe better solutions? I want too keep the html as simple as possible and avoid using the onmouseover attributes within the elements as there are LOT of them..
Target an element with the attribute selector:
$(document).on(
{
mouseenter: function(e)
{
//stuff to do on mouseover
var domNode = this,
$object = $(domNode),
title = domNode.title;
$object.addClass('hover');
console.log(title);
},
mouseleave: function(e)
{
//stuff to do on mouseleave
var domNode = this,
$object = $(domNode),
title = domNode.title;
$object.removeClass('hover');
console.log(title);
}
}
, "[title]");
(Simple) JS Fiddle demo.
References:
on().
Related
I've been looking for so long and found several answers that suggest using .on() as in $('.idOfMyElemenet').on() works even for elements that don't exist yet. But this doesn't seem to be finding the element. Am I doing something wrong?
The highest level <span> (in screenshot) does not exist until I click on a drop-down. Ultimately I'm trying to trigger an event when the user clicks on any of the <li> (aka selects an option from the drop-down).
$(document).ready(function () {
var test = "#select2-id_customer-results";
$(test).on("click", function() {
console.log('hello')
})
})
EDIT:
Thanks to Drew Baker - I think his second solution is the way to go. But not quite there yet...
From the select2 documentation
All public events are relayed using the jQuery event system, and they
are triggered on the <select> element that Select2 is attached to.
So I tried listening to it via the id (which doesn't seem to exist but would probably be id_customer) and the class. The class I added below did not work. Is there a way to listen to this using Jquery?
$(document).ready(function () {
// console.log($('#id_customer'));
$('.modelselect2 form-control select2-hidden-accessible').on('select2:select', function (e) {
var data = e.params.data;
console.log(data);
});
});
I'll answer your question, but then give you a better solution.
First, you need to make sure the thing you are attaching .on() to actually exists. I typically use a containing DIV or failing that body or html will work.
Secondly you are missing a parameter that tells jQuery the thing you are looking to watch to be clicked on. In this case, I'm assuming it is the UL tag with the ID you provided.
This should do what you want:
$(document).ready(function () {
$('body').on("click", "#select2-id_customer-results", function() {
console.log('hello')
})
})
But a better solution would be to use the Select2 API to have it tell you when something is selected. This will be way more reliable and should make your code work after upgrades to Select2.
Something like this:
$('select[name="customer"]').on('select2:select', function (e) {
var data = e.params.data;
console.log(data);
});
NOTE: #mySelect2 is probably not what you have. Use whatever ID you used to initialize Select2 in jQuery.
You can read more about that API here: https://select2.org/programmatic-control/events
if your element is dynamically generated and you want to target that specific element. You need to specify a static container/parent element to indicate where it belongs.
Try this:
$( '#dynamicallyAddedElement' ).on( 'click', '#wrapper', function () { ... });
//where #wrapper is a static parent element in which you add the dynamic links.
So, you have a wrapper which is hard-coded into the HTML source code:
PS. Hope I helped in some way.
If you need to trigger an event when click on <li> elements, you have to use that elements id or class as the selector. Check the below code:
$(document).ready(function () {
var test = ".select2-results__option";
$(test).on("click", function() {
console.log('hello')
})
})
It turns out this is an old bug in django-auto-complete.
The code below works. I have no idea why but now I can move on.
Note: the 'name' is the value of the select2 select element (see screenshot at bottom)
document.querySelector('select[name="customer"]').onchange=function() {
console.log("myselect2name changed");
};
I have a dynamic hover that gets activated based on whether a hidden element exists or not. I'm updating my code to incorporate dynamically created elements but have ran into an issue and don't know how to select a parent.
Previously I used $(".infotip").parent().hover but have updated to:
$(document).on("mouseenter", ".parent-selector", function() {
$(this).find(".infotip").addClass("active");
});
$(document).on("mouseleave", ".parent-selector", function() {
$(this).find(".infotip").removeClass("active");
});
So what needs to happen is I need ".parent-selector" to behave like $(".infotip").parent()
Since the content is dynamic and you mentioned you can't add a class to the parent when it's created, the only way I can think to do this would be to watch for any new elements that have been added and then bind your events.
This function will periodically look for any elements with the .infotip class that does not have our custom events_bound attribute already. If it finds one, it'll add the attribute and then bind the mouse events to the parent. I've included a fiddle illustrating this with dynamic content.
//check for changes in the dom
setInterval(function() {
$('.infotip:not([events_bound])').each(function() {
//add attribute so that we don't re-bind to this element
$(this).attr('events_bound', true);
//now bind the events to the parent
$(this).parent().mouseenter(function() {
$(this).find(".infotip").addClass("active");
})
$(this).parent().mouseleave(function() {
$(this).find(".infotip").removeClass("active");
})
});
}, 500);
https://jsfiddle.net/ybrwv0c8/1/
Of course if there is anything identifiable about the parent, then the best way would be to use a selector for your on. For instance, if there's a dynamically generated ID with a standard structure like parent_13835723, you could do a partial attribute selector like $('[id^=parent_]')
You might also be able to use use the jquery :has pseudoselector like so. However, this searches all descendants for an element, which may not work correctly depending on how your DOM is structured.
$(document).on("mouseenter", ":has('.infotip')", function() {
$(this).children('.infotip').addClass("active");
});
$(document).on("mouseleave", ":has('.infotip')", function() {
$(this).children('.infotip').removeClass("active");
});
However, according to the jquery docs here http://api.jquery.com/has-selector/:
The expression $( "div:has(p)" ) matches a <div> if a <p> exists anywhere
among its descendants, not just as a direct child.
Because :has() is a jQuery extension and not part of the CSS
specification, queries using :has() cannot take advantage of the
performance boost provided by the native DOM querySelectorAll()
method. For better performance in modern browsers, use $(
"your-pure-css-selector" ).has( selector/DOMElement ) instead.
I'm not sure whether the :has or setInterval method would have better performance.
How about
$(".infotip").parent().mouseleave(function() {
$(this).find(".infotip").addClass("active");
}
and
$(".infotip").parent().mouseleave(function() {
$(this).find(".infotip").addClass("active");
}
Reference : https://api.jquery.com/mouseleave/
You can use jQuery's custom :has selector:
$('document').on('mouseenter', ':has(.infotip)', function () {
$(this).find(".infotip").addClass("active");
});
$('document').on('mouseleave', ':has(.infotip)', function () {
$(this).find(".infotip").addClass("active");
});
I haven't tested this, as there is no HTML provided in the question, but the documentation seems to indicate it will do what you want.
As simple as
jQuery(".child").parent().on('mouseenter', function(){
jQuery(this).css('background', '#f00');
});
jQuery(".child").parent().on('mouseleave', function(){
jQuery(this).css('background', '#0ff');
});
DEMO
Edit:- Based on further clarification,
You can attach events to objects when you create them. If you are binding the same events to multiple objects at different times, just create a named function.
OR
A really dirty hack would be to to unbind and rebind the events everytime a hirerchy of elements is added to the DOM.
Something like
var init = function() {
jQuery(".child").parent().off().on('mouseenter', function(){
jQuery(this).css('background', '#f00');
});
jQuery(".child").parent().off().on('mouseleave', function(){
jQuery(this).css('background', '#0ff');
});
};
Just call the method init everytime you add something to the DOM.
how can I target separately elements from a multitude of elements with the same classes or other properties. I cannot add different classes on each element so I need to target each element when I'm working on.
I have tried this so far but it is targeting all elements with input:text because my wrong condition of targeting each separately element working on.
var selector = $('input:radio').prop("checked", true);
var element = $ ('input:text');
$(selector).on('change', function( event ) {
if(this){
$(element).prop('disabled', true);
alert('disable only this element when radio is selected');
}
else{
alert('others input:text not disabled');
$('input:text').prop("disabled", false);
}
})
Fiddle:
By using DOM navigation method, you can do it really easily. Just use this :
var selector = $('input:radio').prop("checked", true);
var element = $ ('input:text');
$(selector).on('change', function( event ) {
var el = $(this).closest('.input-group').find('input:text');
element.prop('disabled', function(){
return !el.is(this);
})
});
Fiddle : http://jsfiddle.net/D2RLR/5874/
For dynamic input, you'll need to use Event delegation (read more here):
//document should be closest static element
$(document).on('change', 'input:radio', function(){
var el = $(this).closest('.input-group').find('input:text');
$('input:text').prop('disabled', function(){
return !el.is(this);
})
})
I don't understand exactly what you're trying to do, but you can use $(this) to target the element that triggered the event instead of trying to use a selector.
I think something like this is what you want:
$(selector).on('change', function( event ) {
$("input:text").prop("disabled", true);
$(this).parent().siblings("input:text").prop("disabled", false);
})
It disables all of the input:text and then enables the one whose radio button was selected.
Try this:
$(selector).on('change', function( event ) {
$('input:text').prop("disabled", false);
$(this).closest('.input-group').find(element).prop('disabled', true);
})
http://jsfiddle.net/D2RLR/5869/
Why not simplify?
Demo Fiddle
$('input:radio').on('change', function (event) {
$('input[type=text]').prop('disabled', false);
$(this).parent().next('input[type=text]').prop('disabled', 'false');
})
As others said, its not exactly clear what you're trying to do, or how general is your question. If the elements matching your selector have exactly the same attributes (including class), you may need to base on the context they are embedded on, or as a last resource, you may be able to base on the order of these elements.
Context: If you're looking for "p.many_like_me" , and you know the element you're trying to match is inside of #parent_id, you just refine your selector as "#parent_id p.many_like_me"
Order: If you know you're looking for the third element on the DOM matching your selector, you can use get() to select it: $("p.many_like_me").get(2) (get takes an index zero-based).
If you need to select them based on an event triggered by a nearby or somehow-related element, then some of the other answers given here are ok.
Let's say I have 10 images on a page, and I want to hide an image when clicking on it.
Each image has an id like: figure1, figure2, figure3, figure i++.
Of course I could write this
$('#figure1').on('click', function() {
$(this).hide();
});
$('#figure2').on('click', function() {
$(this).hide();
});
$('#figure3').on('click', function() {
$(this).hide();
});
and so on but obviously that's not good.
The other thing I thought was creating a function and triggering it with onclick="theFunction(id)", so then I could hide the right image within the function as it knows the id of the image, but when the page loads, obviously JS doesn't know which ID I'm going to delete. How could I make this dynamic?
Any suggestions?
Err I was using class instead of ID in my function :/
function deletePhoto(photo_id, photoPosition) {
$('#photoFigure' + photoPosition).fadeOut(2000);
}
Called like:
<div class="deletePhoto" onclick="deletePhoto({$value['id']}, {$i})">delete</div>
You can give all of them a common class name say figure and use that as the selector:
$('.figure').on('click', function() {
$(this).hide();
});
Or with what you have you could go with attribute starts-with selector
$('[id^="figure"]').on('click', function() {
$(this).hide();
});
or just combine all of them and make a long and ugly selector:
$('#figure1, #figure2, #figure3').on('click', function(){
$(this).hide();
});
For the second part of your question, you can remove those inline click attribute and add a data-attribute save the photoid as is there and just use it to delete, if you have a consistent html structure then you dont event need that, you can select the photo relative to the deletePhoto button.
<div class="deletePhoto" data-photoid="#photoFigure{$i}">delete</div>
and
$('.deletePhoto').on('click', function(){
$($(this).data('photoid')).fadeOut(2000);
//<-- fade out won't delete the element from DOM instead if you really want to remove then try as mentioned below.
//$($(this).data('photoid')).fadeOut(2000, function(){$(this).remove();});
});
OR Could use multiple Select them like this:
Also plz note you are missing ) in your JQ code.
Link : http://api.jquery.com/multiple-selector/
Sample code
$('#figure1,#figure2,#figure2').on('click', function() {
$(this).hide();
});
$(body).on('click','img',function() {
var fig = $(this).attr('id');
$('#' + fig).fadeOut();
});
Here is what I'm doing... I have a textbox that users type something in and click an add icon. This fires some jquery code that adds the item they typed into a span within a "content" div. The generated code has a delete icon that appears on hover and when clicked it should make the span disappear. This works if the code is on the page already (before document load) but if it's dynamically created, it breaks the delete on click functionality.
Here is a JSfiddle so you can see it in action: http://jsfiddle.net/WF32y/
What can I do to fix this? I essentially want to do what happens on here (stackoverflow.com) when you enter tags to a new question.
Use event delegation for dynamically added elements by changing this:
$('a.delete').on('click', function(e) {
Into this:
$(document).on('click', 'a.delete', function(e) {
Fiddle
.on() Direct and delegated events reference
Also, concerning performance, you can attach the handler to a closer ancestor of the dynamically added elements than the document (e.g. a static wrapper element).
You can easily do it with delegate. In your case:
$('#container').delegate('a.delete','click', function(e) {
e.preventDefault();
taskID = $(this).closest('.task')[0].id;
$(this).closest('.task').fadeTo(300, 0, function() {
$(this).animate({
width: 0
}, 200, function() {
$(this).remove();
});
});
});
And by the way FYI:
// jQuery version 1.4.3+
$('#container').delegate('a.delete'...
// jQuery 1.7+
$('#container').on('click', 'a.delete', function(e) {
it is faster and more propery way than:
$(document).on('a.delete'...
or:
$('body').delegate('a.delete'...
or:
$(document).delegate('a.delete'...