Loop over elements in jQuery when element is double clicked - javascript

I'm new to jQuery and Javascript. I'm trying to make a button that I can double click which then loops through all elements in the webpage with a certain class and fades them.
Currently, I'm trying this:
$(".fadeall").dblclick(function() {
$("div.section").each(function(idx,item) {
item.fadeTo(25,inactiveOpacity);
});
});
In my debugger I see the double click happening, but the function in the each call is not being triggered.
I'm believe I'm not matching the div.section elements correctly, but don't know the correct approach.

It should be erroring out since the DOM element doesn't have a .fadeTo() function, you need to wrap the element you're looping over (item) in a jQuery object, like this:
$(item).fadeTo(25,inactiveOpacity);
Or, this works as well, for example:
$(".fadeall").dblclick(function() {
$("div.section").each(function() {
$(this).fadeTo(25,inactiveOpacity);
});
});

Assuming the HTML has <div> elements with the class section, the only other thing I can see that you would need to do is wrap item in a jQuery object.
$(".fadeall").dblclick(function() {
$("div.section").each(function(idx,item) {
// Wrapped "item" so you have access to jQuery methods
$(item).fadeTo(25,inactiveOpacity);
});
});
Since item is the DOM element, it needs to be wrapped with a jQuery object so that it will have access to methods like .fadeTo().
Another approach is to use this in the .each(), which will refer to the DOM element as well.
$(".fadeall").dblclick(function() {
$("div.section").each(function() {
// Wrapped "this" so you have access to jQuery methods
$(this).fadeTo(25,inactiveOpacity);
});
});
EDIT:
Also, make sure the DOM is loaded before your code runs:
// Wrapping code like this ensures that the DOM elements will be
// loaded before your code runs.
$(function() {
$(".fadeall").dblclick(function() {
$("div.section").each(function() {
// Wrapped "this" so you have access to jQuery methods
$(this).fadeTo(25,inactiveOpacity);
});
});
});
This is a shortcut for jQuery's .ready() method, which will ensure that your code doesn't run until the elements are available.

Related

Javascript in AEMto add a class if a checkbox is clicked

I am trying to target a class called 'horizontal-video' in a div within an AEM component and if the author has clicked a checkbox that has an ID of 'coral-id-540' I want to add a second class called 'flipped' to the div. Here is the code I wrote that isn't working. Could someone help me figure out why it's not working? The console does not show errors.
var x = document.getElementsByClassName("horizontal-video");
$('#coral-id-540').change(function(){
if($(this).is(":checked")) {
$(this).addClass("flipped");
} else {
$(this).removeClass("flipped");
}
});
It's quite possible you're not waiting for the DOM to completely load, (or at least have this bit of code below the element in question on the page during page load)
Is your code wrapped in $(document).ready(function(){ //your code });?
Also, be aware that any element that is dynamically added to the page by JavaScript/jQuery after page load will not have a listener attached using the method you're using.
To allow dynamically added elements to be included in your listener, you should target an ancestor node and add the listener to that node. In plain English: attach the listener to a "higher up" element. The safest (although slowest) node being document itself, but it's better to target something closer:
$(document).ready(function () {
var $horizontalVideo = $(".horizontal-video"); //You're using jQuery - why not use it here? Also, I always name jQuery objects with a `$` in front as a shorthand to know it's wrapped in a jQuery object. Plus, a more descriptive name will help you immensely.
//replace parent-of-coral with the ID of a parent element that you know exists on DOM ready:
$("#parent-of-coral").on("change", "#coral-id-540", function (e) { //get used to using "e" as the event variable for preventing default / stopping propagation / etc
$this = $(this); //cache $(this) reference rather than creating another jQuery object each time you use it
if ($this.is(":checked")) {
$this.addClass("flipped");
} else {
$this.removeClass("flipped");
}
});
});

jQuery .<Something that can automatically run a callback function>(). What would it be?

I need something like .load() but that can only work for images and iframes. I would want to do this in order to automatically attach a selector element in "this" variable.
$('document').ready(function({
$('a').<Something to automatically run the stuff below when page is loaded>(function(){
// Placeholder is to store the href somewhere so the link does not go to a webpage atm.
$(this).attr('placeholder',$(this).attr('href'));
$(this).attr('href','javascript:');
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
My Link
I am not sure if you want to achieve this simple thing ? :
$('document').ready(function({
$('a').each(function(){
$(this).attr('placeholder',$(this).attr('href'));
$(this).attr('href','javascript:');
});
});
$('element').each allows to loop over all elements, and you can use $(this) inside closure to modify the element itself.
jQuery supports chaining so the simplest and most likely the most performant answer is:
$('document').ready(function({
$('a').each(function() {
var a$ = $(this);
a$.attr('placeholder',$a.attr('href'))
.attr('href','javascript:void(0)');
});
});
Everytime you call $(this) it has to create a new jQuery wrapper around this which you might as well cache via a variable.

How to select parent using on selector

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.

jquery .live() and .append()

So I'm currently using .append() to add a feature to all of the posts on a webpage, but when additional posts are loaded on the page, the appended features aren't included in the new content — I'm trying to come up with a way to make sure all of the new content has the appended feature too.
$(this).append('<div id="new_feature></div>');
Something like this?
$(this).live().append('<div id="new_feature></div>');
Maybe there's a way to make it constantly appending in a loop perhaps?
There is DOMNodeInserted event:
$('button').click(function() {
$('#appendme').append($('<div class="inner">').text(Math.random()));
})
$('#appendme').on('DOMNodeInserted','.inner',function() {
console.log(this);
});
DEMO
update: this seems not works in IE, try propertychnage event handler also ($('#appendme').on('DOMNodeInserted,propertychange') but i not sure, have no IE to check this right now.
update2: Domnode* seems deprecated according to mdn, they tell to use MutationObserver object instead
update3: seems here is no very crossbrowser solution for MutationEvents, see this answer, so my suggestion would be use code above, if event supported and fallback to setTimeOut or livequery option.
update4:
If you depend only on .append() you can patch jQuery.fn.append() like this:
jQuery.fn.append=function() {
return this.domManip(arguments, true, function( elem ) {
if ( this.nodeType === 1 || this.nodeType === 11 ) {
this.appendChild( elem );
$(elem).trigger('appended');
}
});
};
$('button').click(function() {
$('#appendme').append($('<div class="inner">').text(Math.random()));
})
$('#appendme').on('appended','.inner',function() {
console.log(this);
});
DEMO2
may be more correct is to spoof jQuery.fn.domManip like here
jQuery documentation:
Use of the .live() method is no longer recommended since later versions of jQuery offer better methods that do not have its drawbacks.
You can use setTimeout() function that can check for new <div>s every n milliseconds.
$(function(){
setInterval("Check4NewDivs();",1000);
});
So say this is a div with class="comment newdiv", so when it appears on the page for the first time, it has the class newdiv that will let the function know it was just dynamically created.
function Check4NewDivs(){
$(".comment .newdiv").each(function(){
$(this).append('<div class="new_feature"></div>').removeClass("newdiv");
});
}
It's append not appened.
live is a deprecated event handler. It's not used this way. use on instead.
http://api.jquery.com/live/
So, the following code will run when you click selector.
$(document).on('click', 'selector', function() {
$(this).append('<div id="new_feature></div>');
});
No, there is no standard way to do it like that. There was a proposal of the events that would be fired whenever the DOM elements are inserted etc., but you cannot rely on that.
Instead rely on either:
(preferably) callbacks - just invoke function ensuring existence of such appended snippets, whenever you pull something (but after you successfully pull it from server and insert into DOM, not sooner), or
constant checks - like using in setInterval() or setTimeout(), but this would be unnecessary processing and you will never get instant append, unless you will perform processing-heavy checks all the time,
use the on load function:
$(item).on('load',function(){
$(this).append('<div id="new_feature"></div>');
});
This will add append the item as a callback once the item has been loaded. I would also choose some sort of dynamic ID creator rather than always append stuff with the same ID, but thats just me.
you must bind to an element that already exists on the page. i have written an example where i make appended content live.
DEMO on JSFiddle
HTML
<div id="container">
<div id="features">
</div>
<br />
<a href='#' id='clickme'>click me to add feature</a>
</div>
JS
$(function() {
$('#clickme').on('click', function(e) {
$('#features').append('<div class="new_feature">new feature</div>');
});
$('#features').on('click', '.new_feature', function() {
alert('i am live.');
});
});

jQuery Issue: functions won't work on newly created HTML element

I have two functions: one that creates a new <textarea> when a button is clicked, and a second function that performs an action when the <textarea> is clicked (or blurred, changed, etc.) That second function selects elements based on a class name. It seems that the second function only works on those matching elements that existed when the page was loaded, but it will not activate on any newly created <textarea> elements. Can anyone figure out why and how to fix this? You'll find the code below. Thanks. --Jake
$('#add').click(function() {
$(this).before("<textarea class='test'></textarea>")
})
$('.test').blur(function () {
alert('just a test')
})
The textarea you create isn't around at the time jQuery assigns the action to elements tagged with the .test class. You'll need the live() function to make this work as desired.
$('.test').live('blur', function () {
alert('just a test')
});
Now any element tagged with .test will automatically bind the specified function on blur no matter when it's created.
You can bind it directly:
$('#add').click(function() {
$(this).before("<textarea class='test'></textarea>").prev().blur(function () {
alert('just a test');
});
});
Or place use jQuery's .delegate() method to place a handler on the parent of #add.
$('#add').click(function() {
$(this).before("<textarea class='test'></textarea>")
}).parent().delegate('.test','blur',function() {
alert('just a test');
});
This is a more efficient approach than using .live().

Categories