jQuery click function affecting multiple divs - javascript

I'm trying to use jQuery's click function to apply a hover state to a selected div, without differentiating the div's in the JavaScript. I'm currently using:
$(document).ready(function(){
$(".project").click(function() {
$("a.expand").removeClass("hovered");
$("a.expand").addClass("hovered");
$(".project_full").hide();
var selected_tab = $(this).find("a").attr("href");
$(selected_tab).fadeIn();
return false;
});
With the HTML:
<div class="project first project_gizmoscoop">
<div class="title">
GizmoScoop!
<div class="date">2012</div>
</div>
<a class="expand" title="(Caption)" href="#project_1">GizmoScoop!</a>
</div>
<div class="project project_sc">
<div class="title">
Striking Code
<div class="date">2011</div>
</div>
<a class="expand" title="(Caption)" href="#project_2">Striking Code</a>
</div>
The .hovered class is applied to the clicked link (specific styles from an external CSS file). However, everything is being chosen. (See http://www.codeisdna.com for an example).
I know what I'm doing wrong (I should be specifying the individual ID's or using HTML5 data attributes), but I'm stuck unnecessarily. I feel like a complete newb right now, that I can't do something this simple (although I've done more advanced stuff).

You simply need to take advantage of jQuery's flexibility (and good programming practice) and reduce your scope accordingly. You're already doing something similar with your variable definition. For example, to target only those a.expand elements inside the instance of .project that's clicked:
$(".project").click(function() {
$(this).find("a.expand").removeClass("hovered");
...
});

$(".expand").click(function() {
$(this).addClass("hovered");
..
});

Related

Javascript / Greasemonkey / Userscript.js identify element and remove one of many classes

I've spent far too many hours trying to figure this out and as JavaScript is not my primary language and not yet a jQuery guru I've determined I need to ask for help.
In a case where a generated page has a structure where it has a DIV for some odd reason no ID, multiple non-standard data tag attribute tags, but at least standard style CLASS assignment....however...it has been assigned MULTIPLE classes.
Now, just one of those style classes is such that it has a code event associated that I want to neuter and leave all other classes still assigned. What I've tried there (this list is far from complete I have tried many things):
document.getElementsByClassName('Goodclass01')[0].remove('BADCLASS');
document.querySelectorAll('[data-tag-one="["value",
"value"]"]').remove('BADCLASS');
Various jnode calls that all fail due to claims of being unknown
A couple variations of something referred to as the "location hack" none of
which I could get to work but may have very well have been user error.
Safewindow attempt to just replace BADCLASS javascript function all together
but not ideal explained below.
Here is an example of the kind of structure of the target:
<div id="main">
<div class="main_content" data-tag-id="12345">Some stuff sits above</div>
<a href="SOME LINK" class="Goodclass01 Goodclass02 Goodclass03 BADCLASS"
data-tag-one="["value", "value"]">
</div>
In this example there is a javascript function that fires upon clicking the href link above due to the function being associated with BADCLASS style assignment. So, from lots of searching it seemed like I should be able to grab that DIV by any of the initially assigned classes (since there is unfortunately not a class ID which would make it very easy) but then reassign the list of classes back minus the BADCLASS at page load time. So, by the time the user clicks the link, the BADCLASS has been removed to look like this:
<div id="main">
<div class="main_content" data-tag-id="12345">Some stuff sits above</div>
<a href="SOME LINK" class="Goodclass01 Goodclass02 Goodclass03"
data-tag-one="["value", "value"]">
</div>
I also read that simply using unsafewindow to replace the BADCLASS javascript function could be possible, so I am open to hearing one of you gurus help with how easy (or hard) that would be. In a case where BADCLASS could be shared function code perhaps called by another element on the page still having that initial class that perhaps we desire to continue to function which is why if it is only a single element that needs to be altered, I would rather just change this one href div.
Hope the explanation makes sense and what is probably a laughable simple example above for the Javascript gurus so forgive me but your help is greatly appreciated and will save more hair pulling! :)
EDIT: This must work above all in Chrome browser!
Remove the class from all elements
If you want to remove the class from all elements that have the class, simply select all of the elements with that class and remove the class from their class lists.
[...document.querySelectorAll('.BADCLASS')]
.forEach(e => e.classList.remove('BADCLASS'));
const elements = [...document.querySelectorAll('.BADCLASS')];
elements.forEach(e => e.classList.remove('BADCLASS'));
console.log(elements);
<div id="main">
<div class="main_content" data-tag-id="12345">Some stuff sits above</div>
<a href="SOME LINK" class="Goodclass01 Goodclass02 Goodclass03 BADCLASS"
data-tag-one='["value", "value"]'>link</a>
</div>
Using jQuery:
$('.BADCLASS').removeClass('BADCLASS');
const elements = $('.BADCLASS');
elements.removeClass('BADCLASS');
console.log(elements);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main">
<div class="main_content" data-tag-id="12345">Some stuff sits above</div>
<a href="SOME LINK" class="Goodclass01 Goodclass02 Goodclass03 BADCLASS"
data-tag-one='["value", "value"]'>link</a>
</div>
Remove the class from a subset of elements
If you only want to remove the class from a subset elements, select those elements then from the class from their class lists.
[...document.querySelectorAll('.Goodclass01, .Goodclass02, .Goodclass03')]
.forEach(e => e.classList.remove('BADCLASS'));
const elements = [...document.querySelectorAll('.Goodclass01, .Goodclass02, .Goodclass03')];
elements.forEach(e => e.classList.remove('BADCLASS'));
console.log(elements);
<div id="main">
<div class="main_content" data-tag-id="12345">Some stuff sits above</div>
<a href="SOME LINK" class="Goodclass01 Goodclass02 Goodclass03 BADCLASS"
data-tag-one='["value", "value"]'>link</a>
link
</div>
Using jQuery:
$('.Goodclass01, .Goodclass02, .Goodclass03').removeClass('BADCLASS');
const elements = $('.Goodclass01, .Goodclass02, .Goodclass03');
elements.removeClass('BADCLASS');
console.log(elements);
<div id="main">
<div class="main_content" data-tag-id="12345">Some stuff sits above</div>
<a href="SOME LINK" class="Goodclass01 Goodclass02 Goodclass03 BADCLASS"
data-tag-one='["value", "value"]'>link</a>
link
</div>
Run at document idle
The default for the run-at directive is document-idle, but if for some reason that has been changed, either it needs to be document-idle, or you need to otherwise delay execution of the script until the document has loaded.
You could use the run-at directive in the userscript header like so:
// #run-at document-idle
Or attach a load event listener to the window
window.addEventListener('load', function() { /* do stuff */ }, false);
Include jQuery
If you're using one of the jQuery solutions, you will have to include jQuery using the require userscript header directive like so:
// #require https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js
Got it with the help of both of the clear, awesome correct answers below that literally came in within seconds of each other and only a few min after my post, so thanks to both #Tiny and #Damian below!
I'm upvoting both as they both listed the same correct jQuery answers, and Tiny also provided the pure JS.
I am posting the full answer below because without the other steps, with Tamper/Greasemonkey neither will produce the desired results.
First, Tamper/Greasemonkey do not load jQuery by default, so it is just easy as add #require http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.mi‌​n.js to your current script and also put this.$ = this.jQuery = jQuery.noConflict(true); to avoid any versioning conflicts.
Also, in this case unfortunately I HAD to change my TamperMonkey header to:
// #run-at document-idle
along with the above mentioned:
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js
and begin the script with:
this.$ = this.jQuery = jQuery.noConflict(true);
and finally the primary accepted/best answer in this case of:
$('.Goodclass01').removeClass('BADCLASS');
NOTE: The above #run-at line is required, and since so many (all) of my current Tamper/Greasemonkey scripts are actually set by default to run at START, this is of importance as it means functions like this must be separated to their own scripts to run instead AFTER the page loads (idle). Once this is added, even the above pure JS answer from Tiny did in fact produce the desired result.
As the simplest one-line answer that I was hoping was possible in Javascript, as it is so many other languages in a single line of code. I've used it in the past, but was not aware of this particular removeClass method.
Your question mentions jQuery. Did you want a solution in jQuery?
If so, it's as easy as:
$(".Goodclass01").removeClass("badclass");
Explanation:
jQuery can be referenced as jQuery() or $(). The parameters you can pass are: 1, a Selector statement (like CSS), and 2, context (optional; default is document).
By stating $(".Goodclass01") you are stating, "Give me a jQuery object with all elements that have the class Goodclass01." Then, by using the removeClass() function, you can either pass it no parameters and it would remove all classes, or you can pass it specific classes to remove. In this case, we call .removeClass("badclass") in order to remove the undesired class.
Now, if you need to select only specific elements, such as links that have Goodclass01, you can do:
$("a.GoodClass01").removeClass("badclass");
Or, if you want to select anything that has Goodclass01, but NOT Goodclass02, you can do:
$(".Goodclass01:not(.Goodclass02)").removeClass("badclass");
jQuery is not as intimidating as it looks. Give it a shot!
Edit: I also noticed you were trying to capture a link with maybe a specific property. You can use the [property] syntax to select elements that have a specific property. Most typically, people use $("a[href^=https]") or something to that effect to select all a tags with the property href that begins with ^= the string https.
You could, in your case, use the following...
$("a[data-tag-one]")
... to select all links that have the property data-tag-one.
Note: One thing to keep in mind is that, a jQuery object is different than a pure DOM element. If you have a collection of multiple elements and want to use a pure JavaScript function on one element in particular, you would have to reference it with either [0] or .get(0). Once you do that, you will no longer be able to use jQuery methods until you convert it back to a jQuery object.
But, since jQuery has a whole slew of methods to use to make DOM manipulation easier, you can probably accomplish what you need to using those methods.
Edit: I've included a snippet below so you can see some of the jQuery selectors in action.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<style>
div#main * { background-color: #66ff66; }
div#main .BADCLASS, div#main .BADCLASS * { background-color: #ff8888 !important; }
</style>
<div id="main">
<div class="main_content" data-tag-id="12345">Some stuff sits above</div>
<a href="SOME LINK" class="Goodclass01 Goodclass02 Goodclass03 BADCLASS"
data-tag-one='["value", "value"]'>All classes and data-tag-one</a><br />
<a href="SOME LINK" class="Goodclass01 BADCLASS" data-tag-one='["value", "value"]'>Goodclass01 and data-tag-one</a><br />
All classes, no data-tag-one<br />
<a href="SOME LINK" class="BADCLASS" data-tag-one='["value", "value"]'>Just BADCLASS and data-tag-one</a><br />
<br />
<table class="Goodclass01 BADCLASS"><tr><td>Here is a table</td></tr><tr><td>with Goodclass01 and BADCLASS</td></tr></table>
</div>
<hr>
<div id="buttons">
$(".Goodclass01").removeClass("BADCLASS");<br />
$("a.Goodclass01").removeClass("BADCLASS");<br />
$(".Goodclass01:not(.Goodclass02)").removeClass("BADCLASS");<br />
$("a[data-tag-one]").removeClass("BADCLASS");<br />
Reset the HTML<br />
</div>
<script>
$("#button1").click(function(){
$(".Goodclass01").removeClass("BADCLASS");
});
$("#button2").click(function(){
$("a.Goodclass01").removeClass("BADCLASS");
});
$("#button3").click(function(){
$(".Goodclass01:not(.Goodclass02)").removeClass("BADCLASS");
});
$("#button4").click(function(){
$("a[data-tag-one]").removeClass("BADCLASS");
});
$("#button5").click(function(){
var str = '<div class="main_content" data-tag-id="12345">Some stuff sits above</div>All classes, no data-tag-one<br /><a href="SOME LINK" class="BADCLASS" data-tag-one=\'["value", "value"]\'>Just BADCLASS and data-tag-one</a><br /><br /><table class="Goodclass01 BADCLASS"><tr><td>Here is a table</td></tr><tr><td>with Goodclass01 and BADCLASS</td></tr></table>';
$("div#main").html(str);
});
</script>

passing variables on jquery

just having some issues with this jQuery thing.
What i'm trying to do is:
i have some audio control buttons that look like this:
<p>Play audio</p>
but there are too many on the page so i'm trying to optimise the code and make a little function that checks for the div id on the button and adds tells the player what track to play.
so i've done this:
<div id="audioControlButtons-1">
<div class="speaker"> </div>
<div class="play"> </div>
<div class="pause"> </div>
</div>
<script>
$(document).ready(function() {
$("[id^=audioControlButtons-] div.play").click(function() {
var id = new Number;
id = $(this).parent().attr('id').replace(/audioControlButtons-/, '');
//alert(id);
player1.loadAudio(id);
return false;
});
});
</script>
my problem is:
the id is not passing to the the player1.loadAudio(id)
if i hardcode player1.loadAudio(1)
it works! but the moment i try to pass the variable to the function it doesn't work...
however if you uncomment the alert(id) thing you will see the id is getting generated...
can someone help?
cheers,
dan
I think I see your problem. The variable id is a string. Try;
player1.loadAudio(parseInt(id));
Yah and the initialise line isn't necessary. Just use;
var id = $(this).parent().attr('id').replace(/audioControlButtons-/, '');
I'm actually kind of confused with your example because you originally have this:
<p>Play audio</p>
but then you don't reference it again. Do you mean that this html:
<div id="audioControlButtons-1">
<div class="speaker"> </div>
<div class="play"> </div>
<div class="pause"> </div>
</div>
Is what you are actually creating? If so, then you can rewrite it like this:
<div class="audio-player">
<div class="speaker"> </div>
<div class="play" data-track="1"> </div>
<div class="pause"> </div>
</div>
Then in your script block:
<script>
$(document).ready(function() {
$(".audio-player > .play").click(function() {
var track = $(this).data('track');
player1.loadAudio(+track);
return false;
});
});
</script>
So a few things are going on here.
I just gave your containing div a class (.audio-player) so that it's much more generic and faster to parse. You don't want to do stuff like [id^=audioControlButtons-] because it is much slower for the javascript to traverse and parse the DOM like that. And if you are going to have multiples of the same element on the page, a class is much more suited for that over IDs.
I added the track number you want to the play button as a data attribute (data-track). Using a data attribute allows you to store arbitrary data on DOM elements you're interested on (ie. .play button here). Then this way, you don't need to this weird DOM traversal with a replace method just to get the track number. This saves on reducing unnecessary JS processing and DOM traversing.
With this in mind now, I use jQuery's .data() method on the current DOM element with "track" as the argument. This will then get the data-track attribute value.
With the new track number, I pass that along into your player1.loadAudio method with a + sign in front. This is a little javascript trick that allows you to convert your value into an actual number if that is what the method requires.
There are at least a couple of other optimizations you can do here - event delegation, not doing everything inside the ready event - but that is beyond the scope of this question. Hell, even my implementation could be a little bit optimized, but again, that would require a little bit more in depth explanation.

Difficulty with selective show/hide based on CSS class

I'm working on a js script which will show / hide multiple divs based on css class, seemingly pretty simple. I set out to find an example of this and found something close in the article linked below. I used the code in the following link as a starting point.
Show/hide multiple divs using JavaScript
In my modified code (shown below) I am able to hide all (which is errant) and show all (which works correctly. I'm not sure why its not targeting the CSS class "red, green or blue" correctly. If I hard one of the class names in the script it works as expected, so I'm fairly certain I'm having an issue in the way I'm referencing the css targets themselves.
I am able to hide all and show all, yet I'm having difficulty showing only the selected class.
Here is the jsFiddle I'm working with: http://jsfiddle.net/juicycreative/WHpXz/4/
My code is below.
JavaScript
$('.categories li a').click(function () {
$('.marker').hide();
$((this).attr('target')).show();
});
$('#cat-show').click(function () {
$('.marker').show();
});
HTML
<ul class="categories">
<li id="cat-show" class="cat-col1" target="all" >All</li>
<li id="cat-models" class="cat-col1" target="red" >Model Homes</li>
<li id="cat-schools" class="cat-col1" target="blue">Schools</li>
<li id="cat-hospital" class="cat-col1" target="green" >Hospitals</li>
</ul>
<div id="locator">
<div id="overview-00" class="marker models" title="Maracay Homes<br />at Artesian Ranch"></div>
<!--SCHOOLS-->
<div id="overview-01" class="marker red" title="Perry High School">1</div>
<div id="overview-02" class="marker red" title="Payne Jr. High School">2</div>
<div id="overview-03" class="marker blue" title="Hamilton Prep">3</div>
<div id="overview-04" class="marker blue" title="Ryan Elementary">4</div>
<div id="overview-05" class="marker green" title="Chandler Traditional – Freedom">5</div>
</div>
Thanks in advance for any responses.
$((this).attr('target')).show();
This is syntactically incorrect. It should be $($(this).attr('target'))
However that's no good either because this is the anchor element that does not have the target. Use $(this).closest('li').attr('target') (or add the target to the <a>).
This is also semantically incorrect as that would interpolate to $("red") which would try to look for a <red> element.
$("." + $(this).closest('li').attr('target'))
http://jsfiddle.net/WHpXz/5/
You are almost there. This is the line that needs tweaking: $((this).attr('target')).show();
$(this) actually refers to the current anchor tag that was clicked. Since the anchor tag doesn't have the target attribute, you need to go up to the parent.
From there, you can get the target and add the '.' to the color to use as a selector.
var catToShow = $(this).parent().attr('target');
$('.' + catToShow).show();
I've edited your fiddle. Give it a shot.
http://jsfiddle.net/juicycreative/WHpXz/4/

Easiest way to get element parent

Suppose i have this structure of elements:
<div class="parent">
<div class="something1">
<div class="something2">
<div class="something3">
<div class="something4"></div>
</div>
</div>
</div>
</div>
And code like this:
$(".something4").click(function(){
//i could do it like this...
$(this).parent().parent().parent().parent().parent();
});
But that seems to be stupid, is there a better way to do this?
also i can't just say $(.parent) because there are many divs like this with class parent in my page.
Use .closest(selector). This gets the first element that matches the selector, beginning at the current element and progressing up through the DOM tree.
$('.something4').click(function() {
$(this).closest('.parent');
});
Use .closest():
$('.something4').click(function() {
$(this).closest('.parent');
});
I think you should try this
$(this).parents(".parent");
But I don't know where on the page are the other divs with this class :)
You could always use .parentNode (standard JavaScript). It's generally a bad idea to use class names that coincide with function/variable names from the library you're using (this goes for any language). Making your class names more unique is a better approach (for instance, "scparent" instead of "parent", if the name of your application was "Super Calculator" or something). This avoids conflicts such as the one you're describing.
I would caution using .closest(), simply because you may create a function like this:
function getParentElem() {
return $(this).closest('div');
}
And it would grab the parent div's in your code just fine, but if down the road you add a table for displaying data, and you run the function through a child element of the table, you will have to create another implementation that selects the table element, because that's what you now want:
<div id="tableParent">
<table id="dataTable">
<tr id="target1">
<td>Some data.</td>
</tr>
</table>
</div>
By using your function getParentElem() on the tr element, you'll end up grabbing the div with id="tableParent", rather than the actual parent, which is the table element. So, unless you've delineated your parent classes appropriately all the way through your code (which can be a pain and isn't always efficient), you may run into problems. Especially if at any point you're creating elements programmatically, or reading in data from another 3rd-party library or script.
Not saying it's not good to use .closest()... just pointing out a possible "gotcha".
i would suggest adding to the div parent an id like 'parent_1' etc. and in every son you keep the id in the rel attr
<div id="parent_1" class="parent">
<div rel="1" class="something1">
<div rel="1" class="something2">
<div rel="1" class="something3">
<div rel="1" class="something4"></div>
</div>
</div>
</div>
</div>
$(".something4").click(function(){
//i could do it like this...
$('#parent_' + $(this).attr('rel'));
});

from plain javascript to dojo framework

I've started to learn the dojo Toolkit and i like it so far, it seems to me easier to understand than jquery/prototype JS. I'm still new at it (and in javascript) and while there is a plethora of docs available on the net i don't really understand how to achieve simple tasks like making a hidden visible with dojo. So to the problem:
the html
<!-- the numder in id="comment" and in href="javascript:display_comments('')" is the post_id that i want the comments to be fetched for -->
<div class="comments">
<a id="comment8" href="javascript:display_comments('8');">comments</a>(21)
</div>
<div style="visibility: hidden;" id="display_comments8">
</div>
<div class="comments">
<a id="comment7" href="javascript:display_comments('7');">comments</a>(13)
</div>
<div style="visibility: hidden;" id="display_comments7">
</div>
<div class="comments">
<a id="comment15" href="javascript:display_comments('15');">comments</a>(20)
</div>
<div style="visibility: hidden;" id="display_comments8">
</div>
the javascript
function display_comments(id) {
divid = 'display_comments'+id;
var element = document.getElementById(divid);
if(element.style.visibility == 'hidden') {
element.style.visibility='visible'
}else if(element.style.visibility == 'visible') {
element.style.visibility='hidden';
element.innerHTML='';
}
}
The parameter for display_comments() in the post_id which then is merged with the words 'display_comments' so to know which div to make visible. How can this be achieved in dojo?
Basically what you want to do here is automate things a bit right? If you attribute your links either by id, like i use below, or some other way (non validatable properties or html5 data-attributes) then you can use dojo.query to find all the nodes in your container and attach an event to them. I gave you a link to the dojo.query syntax page in case you wanted to make your query syntax more specific.
After looping through all the a nodes in container and attaching a click event with a handler that passes the node's id (the dojo.partial stuff), you just need to handle the click event. The toggle display uses dojo core to change and modify the style of the node - pretty simple.
Based on your example this is how I would change your code.
There are a lot of ways you could achieve these results. Personally, I would create templated widgets. Since this code looks repetitive, you could dojo.declare a comment class and dojoattachevents to the links and dojoattachpoint to the hidden node. This way you wouldn't have to dojo.query or dojo.byId since widget would wire all that up for you. You could create one for each and use class syntax to handle the logic.
<div id="container">
<div class="comments">
<a id="8">comments</a>(21)
</div>
<div style="visibility: hidden;" id="display_comments8">
</div>
<div class="comments">
<a id="7">comments</a>(13)
</div>
<div style="visibility: hidden;" id="display_comments7">
<div>
dojo.query reference
dojo.query("#container a").forEach(function(node) {
dojo.connect reference
dojo.partial reference
dojo.connect(node, 'onclick', dojo.partial(toggleDisplay, node.id));
});
dojo.byId reference
dojo.style reference
function toggleDisplay(node) {
var hiddenNode = dojo.byId('display_comments' + node);
var display = dojo.style(hiddenNode).visibility === 'visible' ? 'hidden' : 'visible';
dojo.style(hiddenNode, {
visibility: display
});
}
Working Example
jsfiddle example
Books
we have dojo the definitive guide and mastering dojo and getting startED with dojo.
PS all these books are outdated and the best information is found on the test pages/the irc #dojo chat room/and the reference guides.

Categories

Resources