How to use javascript to add classes to text and image - javascript

I would really appreciate help with running a query for .parentContainer, then find text ABC123 and wrap this in a div with ID="abc123". I already have some simple code that will add content to the new div element.
Further to that, is it possible to also query .parentContainer for the presence of ABC123, and then add a new class to the image if ABC123 exists?
Sorry if I appear a bit lazy here. I have really only started dabbling with JavaScript and have been reading lots on manipulation of the DOM. I tend to learn loads from studying and tweaking code that can apply to my own real scenarios.
Thanks so much!
let parentContainers = document.querySelectorAll('.parentContainer')
for(let [i,f] of parentContainers.entries()){
if(f.innerText.includes('ABC123')){
let div = document.createElement('div');
div.innerText = 'ABC123';
div.setAttribute("id", "abc123");
f.append(div)
}
}
#ABC123 {
border: 3px solid red;
}
#abc123 {
border: 3px solid green;
}
.abc123 {
border: 2px solid purple;
}
.parentContainer {
padding: 10px;
border: 2px solid black;
margin: 10px 0;
}
<div class="parentContainer">
<a class="productImage" href="https://www.mywebsite.com/product-1"><img src="https://via.placeholder.com/350x150" alt="Product 1 Image"></a>
<div class="productInfo">
ABC123
Product summary description goes here.
</div>
</div>
<div class="parentContainer">
<a class="productImage" href="https://www.mywebsite.com/product-1"><img src="https://via.placeholder.com/350x150" alt="Product 1 Image"></a>
<div class="productInfo">
ABC123
Product summary description goes here.
</div>
</div>

Try this out
let parentContainers = document.querySelectorAll('.parentContainer')
for(let [i,f] of parentContainers.entries()){
if(f.innerText.includes('ABC123')){
let div = document.createElement('div');
div.innerText = 'ABC123';
div.setAttribute("id", "abc123");
f.append(div)
}
}

Related

How to use onclick event in JavaScript?

I'm trying to make a window that slide up when the X button(close.png) is clicked.
I added the Wrap element with JavaScript, and added an img element inside.
Then, I put following JavaScript, but there is no change when I press the X button.
<script>
const parent3 = document.querySelector('#wrap');
const billingField3 = document.querySelector('#woocommerce-input-wrapper');
const newImg = document.createElement('img');
newImg.setAttribute("src", "//t1.daumcdn.net/postcode/resource/images/close.png");
newImg.setAttribute('id', 'btnFoldWrap');
newImg.style.cssText = 'cursor:pointer;position:absolute;right:0px;top:-1px;z-index:1';
newImg.onclick = "offDaumZipAddress();"
parent3.insertBefore(newImg, billingField3);
</script>
function offDaumZipAddress() {
jQuery("#wrap").slideUp();
}
Website structure is
<div class="woocommerce-billing-fields__field-wrapper">
<p class="billing_postcode_find_field">..
<span class="woocommerce-input-wrapper">...
</span>
</p>
<div id="wrap" ..>
<img src="..."></img>
</div>
<p class="billing_address_1_field">
<span class="woocommerce-input-wrapper">
Checking with the console of chrome developer tools doesn't show any errors.
Could someone please let me know what am I missing?
Thank you.
The value of the onclick property must be a function reference, not a JavaScript string.
newImg.onclick = offDaumZipAddress;
You have your answer; here is a working example of that loosely based on your code (so the inserted image actually shows, added some CSS etc. to illustrate)
//gets first one of this type
const billingField3 = document.querySelector('.woocommerce-input-wrapper');
// Get a reference to the parent node/ gets first one of this type
const parent3 = billingField3.parentNode;
//console.log(parent3);
//console.log(billingField3);
// Create the new node to insert
const newImg = document.createElement('img');
newImg.setAttribute("src", "//t1.daumcdn.net/postcode/resource/images/close.png");
newImg.setAttribute('id', 'btnFoldWrap');
newImg.setAttribute('alt', 'folderWrap');
// no not this: newImg.style.cssText = 'cursor:pointer;position:absolute;right:0px;top:-1px;z-index:1';
// this:
newImg.classList.add("inserted-image");
newImg.onclick = offDaumZipAddress;
//console.log("Thing:",newImg);
//console.log("HTML:", parent3.innerHTML);
parent3.insertBefore(newImg, billingField3);
//console.log("New HTML:", parent3.innerHTML);
function offDaumZipAddress() {
console.log('here we go');
jQuery("#wrap").slideUp();
}
.billing_postcode_find_field {
border: solid blue 1px;
padding: 1rem;
}
.woocommerce-input-wrapper {
border: solid 1px lime;
padding: 1rem;
}
.inserted-image {
cursor: pointer;
/* This is odd, makes it not clickable:
position: absolute;
right: 0px;
top: -1px;
z-index: 1;*/
border: solid 1px red;
min-width: 1.5rem;
min-height: 1.5rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="woocommerce-billing-fields__field-wrapper">
<p class="billing_postcode_find_field">..
<span class="woocommerce-input-wrapper">...</span>
</p>
<div id="wrap">
<img src="//t1.daumcdn.net/postcode/resource/images/close.png" alt="png"></img>
</div>
<p class="billing_address_1_field">
<span class="woocommerce-input-wrapper"></span>
</div>

Applying css to a javascript variable

I want to add color and border to a javascript variable using css. Below is my code;
var msg = "OK"; //i want this to colored and bordered with green.
msg = "Conflict"; // i want this to be colored and bordered with red.
I tried another answer from other questions but it doesn't seem to work with me.
If you're just trying to add styles to a JavaScript variable you can't do that, and I don't understand what you would hope to achieve by doing that.
I am therefore going to assume you want to add styles to an html element that you have extracted as a JavaScript variable like so
let msgElement = document.getElementById('msg')
let msg = "OK"
msgElement.innerHTML = msg
In this case, you can add styles to the element like so
msgElement.style.color = "red"
msgElement.style.border = "2px solid red"
In your example, when you change the value of msg to "Conflict", you are doing just that - changing it. You can't have two separate values held by the same variable.
As one of the comments says, this is basic web development, so I would advise some further reading, or an online course such as those provided by Codeacademy
As the other answers state, you can't apply a CSS rule to a variable. You can, however, do something like this:
<html>
<head>
<style>
.redgreen {border-style: solid; border-color: green; color: red;}
</style>
<script>
function foo() {
let msg = "<div class='redgreen'>Hello, world!</div>";
document.getElementById("themsg").innerHTML = msg;
}
</script>
</head>
<body onload='foo();'>
<p id='themsg'>Your message here</p>
</body>
</html>
That is, define "msg" as an HTML element instead of a text string.
You can't add CSS to a javascript variable.
if you are create element using javascript
html:
<div class="parent-div">
</div>
js:
var msg = "OK";
element = document.createElement('p');
// Give the new element some content and css
element.innerHTML = msg;
element.style.color = 'green';
element.style.border = "1px solid red";
// append element to parent div
document.querySelector('.parent-div').appendChild(element);
Just do without javascript
html:
<div class="parent-div">
<p class="child-one">OK</p>
<p class="child-two">Conflict</p>
</div>
css:
.parent-div .child-one {
color: red;
border: 1px solid green;
}
.parent-div .child-two {
color: green;
border: 1px solid red;
}

trying to collapse text [duplicate]

I have created a list on my site. This list is created by a foreach loop that builds with information from my database. Each item is a container with different sections, so this is not a list like 1, 2, 3... etc. I am listing repeating sections with information. In each section, there is a subsection. The general build is as follows:
<div>
<fieldset class="majorpoints" onclick="majorpointsexpand($(this).find('legend').innerHTML)">
<legend class="majorpointslegend">Expand</legend>
<div style="display:none" >
<ul>
<li></li>
<li></li>
</ul>
</div>
</div>
So, I am trying to call a function with onclick="majorpointsexpand($(this).find('legend').innerHTML)"
The div I am trying to manipulate is style="display:none" by default, and I want to use javascript to make it visible on click.
The "$(this).find('legend').innerHTML" is attempting to pass, in this case, "Expand" as an argument in the function.
Here is the javascript:
function majorpointsexpand(expand)
{
if (expand == "Expand")
{
document.write.$(this).find('div').style = "display:inherit";
document.write.$(this).find('legend').innerHTML = "Collapse";
}
else
{
document.write.$(this).find('div').style = "display:none";
document.write.$(this).find('legend').innerHTML = "Expand";
}
}
I am almost 100% sure my problem is syntax, and I don't have much of a grasp on how javascript works.
I do have jQuery linked to the document with:
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
In the <head></head> section.
Okay, so you've got two options here :
Use jQuery UI's accordion - its nice, easy and fast. See more info here
Or, if you still wanna do this by yourself, you could remove the fieldset (its not semantically right to use it for this anyway) and create a structure by yourself.
Here's how you do that. Create a HTML structure like this :
<div class="container">
<div class="header"><span>Expand</span>
</div>
<div class="content">
<ul>
<li>This is just some random content.</li>
<li>This is just some random content.</li>
<li>This is just some random content.</li>
<li>This is just some random content.</li>
</ul>
</div>
</div>
With this CSS: (This is to hide the .content stuff when the page loads.
.container .content {
display: none;
padding : 5px;
}
Then, using jQuery, write a click event for the header.
$(".header").click(function () {
$header = $(this);
//getting the next element
$content = $header.next();
//open up the content needed - toggle the slide- if visible, slide up, if not slidedown.
$content.slideToggle(500, function () {
//execute this after slideToggle is done
//change text of header based on visibility of content div
$header.text(function () {
//change text based on condition
return $content.is(":visible") ? "Collapse" : "Expand";
});
});
});
Here's a demo : http://jsfiddle.net/hungerpain/eK8X5/7/
how about:
jQuery:
$('.majorpoints').click(function(){
$(this).find('.hider').toggle();
});
HTML
<div>
<fieldset class="majorpoints">
<legend class="majorpointslegend">Expand</legend>
<div class="hider" style="display:none" >
<ul>
<li>cccc</li>
<li></li>
</ul>
</div>
</div>
Fiddle
This way you are binding the click event to the .majorpoints class an you don't have to write it in the HTML each time.
You might want to give a look at this simple Javascript method to be invoked when clicking on a link to make a panel/div expande or collapse.
<script language="javascript">
function toggle(elementId) {
var ele = document.getElementById(elementId);
if(ele.style.display == "block") {
ele.style.display = "none";
}
else {
ele.style.display = "block";
}
}
</script>
You can pass the div ID and it will toggle between display 'none' or 'block'.
Original source on snip2code - How to collapse a div in html
So, first of all, your Javascript isn't even using jQuery. There are a couple ways to do this. For example:
First way, using the jQuery toggle method:
<div class="expandContent">
Click Here to Display More Content
</div>
<div class="showMe" style="display:none">
This content was hidden, but now shows up
</div>
<script>
$('.expandContent').click(function(){
$('.showMe').toggle();
});
</script>
jsFiddle: http://jsfiddle.net/pM3DF/
Another way is simply to use the jQuery show method:
<div class="expandContent">
Click Here to Display More Content
</div>
<div class="showMe" style="display:none">
This content was hidden, but now shows up
</div>
<script>
$('.expandContent').click(function(){
$('.showMe').show();
});
</script>
jsFiddle: http://jsfiddle.net/Q2wfM/
Yet a third way is to use the slideToggle method of jQuery which allows for some effects. Such as $('#showMe').slideToggle('slow'); which will slowly display the hidden div.
Many problems here
I've set up a fiddle that works for you: http://jsfiddle.net/w9kSU/
$('.majorpointslegend').click(function(){
if($(this).text()=='Expand'){
$('#mylist').show();
$(this).text('Colapse');
}else{
$('#mylist').hide();
$(this).text('Expand');
}
});
try jquery,
<div>
<a href="#" class="majorpoints" onclick="majorpointsexpand(" + $('.majorpointslegend').html() + ")"/>
<legend class="majorpointslegend">Expand</legend>
<div id="data" style="display:none" >
<ul>
<li></li>
<li></li>
</ul>
</div>
</div>
function majorpointsexpand(expand)
{
if (expand == "Expand")
{
$('#data').css("display","inherit");
$(".majorpointslegend").html("Collapse");
}
else
{
$('#data').css("display","none");
$(".majorpointslegend").html("Expand");
}
}
Here there is my example of animation a staff list with expand a description.
<html>
<head>
<style>
.staff { margin:10px 0;}
.staff-block{ float: left; width:48%; padding-left: 10px; padding-bottom: 10px;}
.staff-title{ font-family: Verdana, Tahoma, Arial, Serif; background-color: #1162c5; color: white; padding:4px; border: solid 1px #2e3d7a; border-top-left-radius:3px; border-top-right-radius: 6px; font-weight: bold;}
.staff-name { font-family: Myriad Web Pro; font-size: 11pt; line-height:30px; padding: 0 10px;}
.staff-name:hover { background-color: silver !important; cursor: pointer;}
.staff-section { display:inline-block; padding-left: 10px;}
.staff-desc { font-family: Myriad Web Pro; height: 0px; padding: 3px; overflow:hidden; background-color:#def; display: block; border: solid 1px silver;}
.staff-desc p { text-align: justify; margin-top: 5px;}
.staff-desc img { margin: 5px 10px 5px 5px; float:left; height: 185px; }
</style>
</head>
<body>
<!-- START STAFF SECTION -->
<div class="staff">
<div class="staff-block">
<div class="staff-title">Staff</div>
<div class="staff-section">
<div class="staff-name">Maria Beavis</div>
<div class="staff-desc">
<p><img src="http://www.craigmarlatt.com/canada/images/security&defence/coulombe.jpg" />Maria earned a Bachelor of Commerce degree from McGill University in 2006 with concentrations in Finance and International Business. She has completed her wealth Management Essentials course with the Canadian Securities Institute and has worked in the industry since 2007.</p>
</div>
<div class="staff-name">Diana Smitt</div>
<div class="staff-desc">
<p><img src="http://www.craigmarlatt.com/canada/images/security&defence/coulombe.jpg" />Diana joined the Diana Smitt Group to help contribute to its ongoing commitment to provide superior investement advice and exceptional service. She has a Bachelor of Commerce degree from the John Molson School of Business with a major in Finance and has been continuing her education by completing courses.</p>
</div>
<div class="staff-name">Mike Ford</div>
<div class="staff-desc">
<p><img src="http://www.craigmarlatt.com/canada/images/security&defence/coulombe.jpg" />Mike: A graduate of École des hautes études commerciales (HEC Montreal), Guillaume holds the Chartered Investment Management designation (CIM). After having been active in the financial services industry for 4 years at a leading competitor he joined the Mike Ford Group.</p>
</div>
</div>
</div>
<div class="staff-block">
<div class="staff-title">Technical Advisors</div>
<div class="staff-section">
<div class="staff-name">TA Elvira Bett</div>
<div class="staff-desc">
<p><img src="http://www.craigmarlatt.com/canada/images/security&defence/coulombe.jpg" />Elvira has completed her wealth Management Essentials course with the Canadian Securities Institute and has worked in the industry since 2007. Laura works directly with Caroline Hild, aiding in revising client portfolios, maintaining investment objectives, and executing client trades.</p>
</div>
<div class="staff-name">TA Sonya Rosman</div>
<div class="staff-desc">
<p><img src="http://www.craigmarlatt.com/canada/images/security&defence/coulombe.jpg" />Sonya has a Bachelor of Commerce degree from the John Molson School of Business with a major in Finance and has been continuing her education by completing courses through the Canadian Securities Institute. She recently completed her Wealth Management Essentials course and became an Investment Associate.</p>
</div>
<div class="staff-name">TA Tim Herson</div>
<div class="staff-desc">
<p><img src="http://www.craigmarlatt.com/canada/images/security&defence/coulombe.jpg" />Tim joined his father’s group in order to continue advising affluent families in Quebec. He is currently President of the Mike Ford Professionals Association and a member of various other organisations.</p>
</div>
</div>
</div>
</div>
<!-- STOP STAFF SECTION -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script language="javascript"><!--
//<![CDATA[
$('.staff-name').hover(function() {
$(this).toggleClass('hover');
});
var lastItem;
$('.staff-name').click(function(currentItem) {
var currentItem = $(this);
if ($(this).next().height() == 0) {
$(lastItem).css({'font-weight':'normal'});
$(lastItem).next().animate({height: '0px'},400,'swing');
$(this).css({'font-weight':'bold'});
$(this).next().animate({height: '300px',opacity: 1},400,'swing');
} else {
$(this).css({'font-weight':'normal'});
$(this).next().animate({height: '0px',opacity: 1},400,'swing');
}
lastItem = $(this);
});
//]]>
--></script>
</body></html>
Fiddle
Take a look at toggle() jQuery function :
http://api.jquery.com/toggle/
Also, innerHTML jQuery Function is .html().
Since you have jQuery on the page, you can remove that onclick attribute and the majorpointsexpand function. Add the following script to the bottom of you page or, preferably, to an external .js file:
$(function(){
$('.majorpointslegend').click(function(){
$(this).next().toggle().text( $(this).is(':visible')?'Collapse':'Expand' );
});
});
This solutionshould work with your HTML as is but it isn't really a very robust answer. If you change your fieldset layout, it could break it. I'd suggest that you put a class attribute in that hidden div, like class="majorpointsdetail" and use this code instead:
$(function(){
$('.majorpoints').on('click', '.majorpointslegend', function(event){
$(event.currentTarget).find('.majorpointsdetail').toggle();
$(this).text( $(this).is(':visible')?'Collapse':'Expand' );
});
});
Obs: there's no closing </fieldset> tag in your question so I'm assuming the hidden div is inside the fieldset.
If you used the data-role collapsible e.g.
<div id="selector" data-role="collapsible" data-collapsed="true">
html......
</div>
then it will close the the expanded div
$("#selector").collapsible().collapsible("collapse");
Pure javascript allowing only one expanded div at a time. It allows multi-level sub-expanders. The html only need the expanders contents. The javascript will create the expanders headers with the titles form the content data attribute and a svg arrow.
<style>
/* expanders headers divs */
.expanderHead {
color: white;
background-color: #1E9D8B;
border: 2px solid #1E9D8B;
margin-top: 9px;
border-radius: 6px;
padding: 3px;
padding-left: 9px;
cursor: default;
font-family: Verdana;
font-size: 14px;
}
.expanderHead:first-child {
margin-top: 0 !important;
}
.expanderBody:last-child {
margin-bottom: 0 !important;
}
/* expanders svg arrows */
.expanderHead svg > g > path {
fill: none;
stroke: white;
stroke-width: 2;
stroke-miterlimit: 5;
pointer-events: stroke;
}
/* expanders contents divs */
.expanderBody {
border: 2px solid #1E9D8B;
border-top: 0;
background-color: white;
border-top-left-radius: 0;
border-top-right-radius: 0;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
padding: 6px;
font-family: Verdana;
font-size: 12px;
}
/* widget window */
.widget {
width: 400px;
background-color: white;
padding: 9px;
border: 2px solid #1E9D8B;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
}
</style>
<div class="widget">
<div data-title="expander 1" class="expanderBody">
expander 1 content
</div>
<div data-title="expander 2" class="expanderBody">
expander 2 content
</div>
<div data-title="expander 3" class="expanderBody">
<div>
expander 3 content
</div>
<div data-title="expander 3.1" class="expanderBody">
expander 3.1 content
</div>
<div data-title="expander 3.2" class="expanderBody">
expander 3.2 content
</div>
<div data-title="expander 3.3" class="expanderBody">
expander 3.3 content
</div>
</div>
</div>
<script>
document.querySelectorAll(".expanderBody").forEach(item => {
if (item.dataset.title) {
// create expander header
let divHeader = document.createElement("div");
divHeader.className = "expanderHead";
divHeader.innerHTML = "<svg width='14px' height='8px' viewBox='0 0 12 6'><g><path d='M 5 5 L 10 1'/><path d='M 1 1 L 5 5'/></g></svg> <span>" + item.dataset.title + "</span>";
// expander click event
divHeader.addEventListener("click", function () {
// open / close expander
for (let i = 0; i < this.parentNode.children.length; i++) {
let expander = this.parentNode.children[i];
// check if it's expander header
if (expander.className == "expanderHead") {
if (expander == this && expander.nextElementSibling.style.display == "none") {
// open expander body
expander.nextElementSibling.style.display = "";
expander.innerHTML = "<svg width='14px' height='8px' viewBox='0 0 12 6'><g><path d='M 1 5 L 5 1'/><path d='M 5 1 L 10 5'/></g></svg> <span>" + expander.nextElementSibling.dataset.title + "</span>";
expander.style.borderBottomLeftRadius = "0";
expander.style.borderBottomRightRadius = "0";
}
else {
// close expander body
expander.nextElementSibling.style.display = "none";
expander.innerHTML = "<svg width='14px' height='8px' viewBox='0 0 12 6'><g><path d='M 5 5 L 10 1'/><path d='M 1 1 L 5 5'/></g></svg> <span>" + expander.nextElementSibling.dataset.title + "</span>";
expander.style.borderBottomLeftRadius = "6px";
expander.style.borderBottomRightRadius = "6px";
}
}
}
}, true);
item.parentNode.insertBefore(divHeader, item);
item.style.display = "none";
}
});
</script>
Check out Jed Foster's Readmore.js library.
It's usage is as simple as:
$(document).ready(function() {
$('article').readmore({collapsedHeight: 100});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<script src="https://fastcdn.org/Readmore.js/2.1.0/readmore.min.js" type="text/javascript"></script>
<article>
<p>From this distant vantage point, the Earth might not seem of any particular interest. But for us, it's different. Consider again that dot. That's here. That's home. That's us. On it everyone you love, everyone you know, everyone you ever heard of, every human being who ever was, lived out their lives. The aggregate of our joy and suffering, thousands of confident religions, ideologies, and economic doctrines, every hunter and forager, every hero and coward, every creator and destroyer of civilization, every king and peasant, every young couple in love, every mother and father, hopeful child, inventor and explorer, every teacher of morals, every corrupt politician, every "superstar," every "supreme leader," every saint and sinner in the history of our species lived there – on a mote of dust suspended in a sunbeam.</p>
<p>Space, the final frontier. These are the voyages of the starship Enterprise. Its five year mission: to explore strange new worlds, to seek out new life and new civilizations, to boldly go where no man has gone before!</p>
<p>Here's how it is: Earth got used up, so we terraformed a whole new galaxy of Earths, some rich and flush with the new technologies, some not so much. Central Planets, them was formed the Alliance, waged war to bring everyone under their rule; a few idiots tried to fight it, among them myself. I'm Malcolm Reynolds, captain of Serenity. Got a good crew: fighters, pilot, mechanic. We even picked up a preacher, and a bona fide companion. There's a doctor, too, took his genius sister out of some Alliance camp, so they're keeping a low profile. You got a job, we can do it, don't much care what it is.</p>
<p>Space, the final frontier. These are the voyages of the starship Enterprise. Its five year mission: to explore strange new worlds, to seek out new life and new civilizations, to boldly go where no man has gone before!</p>
</article>
Here are the available options to configure your widget:
{
speed: 100,
collapsedHeight: 200,
heightMargin: 16,
moreLink: 'Read More',
lessLink: 'Close',
embedCSS: true,
blockCSS: 'display: block; width: 100%;',
startOpen: false,
// callbacks
blockProcessed: function() {},
beforeToggle: function() {},
afterToggle: function() {}
},
Use can use it like:
$('article').readmore({
collapsedHeight: 100,
moreLink: 'Continue reading...',
});
I hope it helps.
Using Pure Javascript
const collapsableBtn = document.querySelectorAll('.collapsable-toggle');
for (let index = 0; index < collapsableBtn.length; index++) {
collapsableBtn[index].addEventListener('click', function(e) {
// e.preventDefault();
e.stopImmediatePropagation();
iterateElement = this;
getCollapsableParent = iterateElement.parentElement;
if(getCollapsableParent.classList.contains('show')) {
getCollapsableParent.classList.remove('show')
iterateElement.innerText = iterateElement.getAttribute('data-onCloseText');
} else {
getCollapsableParent.classList.add('show');
iterateElement.innerText = iterateElement.getAttribute('data-onOpenText');
}
})
}
.collapsable-container #expand {
display:none;
}
.collapsable-container.show #expand {
display:block;
}
<div class="collapsable-container">
Show First Content
<div id="expand">
This is some Content
</div>
</div>
<div class="collapsable-container">
Show Second Content
<div id="expand">
This is some Content
</div>
</div>

How to use JavaScript to Alter CSS for Multiple Elements

I am trying to use JavaScript to change the background color of an element after being selected, and also to make sure that only one element at a time has the particular background color. Once the user selects on a different element I would like the previous element that was selected to be replaced by a different background color. Currently I am only able to toggle individual elements by selecting on EACH element. I need to be able to select on an element and apply the new background color, then have JavaScript change the background color of the previously active element to a different color (one less click).
What I am trying to do is very similar to modern navbars or list items where only one element at a time is “active” and has a background color that is different than the other elements in the same div, row, etc.
Notes about my work I am utilizing bootstrap and have no desire to use jQuery for this particular project.
CSS:
<!DOCTYPE html>
<html lang="en">
<head>
<style>
h4 {
border: 1px solid black;
border-radius: 8px;
padding: 10px 2px 10px 2px;
margin: 20px 20px 0px 20px;
background-color: #F0F0F0;
border-color: #F8F8F8;
color: #505050;
cursor: pointer;
}
.active {
background-color: #99E6FF;
}
</style>
</head>
</html>
HTML:
<div id="pTwoRowOne">
<div class="row">
<div class="col-md-4 row row-centered">
<h4 id="techBio" class="test">Biology</h4>
</div>
<div class="col-md-4 row row-centered">
<h4 id="techCart" class="test">Cartography</h4>
</div>
<div class="col-md-4 row row-centered">
<h4 id="techChem" class="test">Chemistry</h4>
</div>
</div>
</div>
JavaScript:
document.getElementById("techBio").onclick=function() {
document.getElementById("techBio").classList.toggle('active');
}
document.getElementById("techCart").onclick=function() {
document.getElementById("techCart").classList.toggle('active');
}
document.getElementById("techChem").onclick=function() {
document.getElementById("techChem").classList.toggle('active');
}
An example can be seen here: http://jsbin.com/fugogarove/1/edit?html,css,js,output
If clarification is needed let me know.
Yup, pretty straightforward.
Assumptions
You're not trying to support IE8, since you're using classList
You're okay with housing your elements as variables as opposed to repeatedly querying the DOM.
Example
JSBin
Code
I rewrote your JavaScript to make it a little bit cleaner and to DRY it up a bit:
var techs = [].slice.call(document.querySelectorAll('#pTwoRowOne h4'));
function set_active(event) {
techs.forEach(function(tech){
if (event.target == tech) { return; }
tech.classList.remove('active');
});
event.target.classList.toggle('active');
}
techs.forEach(function(item) {
item.addEventListener('click', set_active);
});
Some explanation
[].slice.call(document.querySelectorAll('#pTwoRowOne h4')); – We're using this to change the output from a NodeList to an Array. This allows us to use forEach later. querySelectorAll returns a NodeList that contains all elements matching the CSS selector. You can probably replace that with a better CSS selector depending on your environment.
addEventListener is a much nicer way than the iterative add via onclick += to bind an event listener. It's also the recommended way (as far as I know) in ECMA5 and later.
By setting the element queries as variables, you'll be able to keep the reference in memory instead of polling the DOM every time to alter elements. That'll make your JavaScript marginally faster, and it's again just a nicer, cleaner version of the code which it produces.
updates
I reworked the JS to make more sense.
Assuming you only ever have one active element, you can find it using document.querySelector() - if you can have multiples you can use document.querySelectorAll() and iterate through them.
Simple case:
function activate(event) {
var active=document.querySelector('.active');
// activate the clicked element (even if it was already active)
event.target.classList.add('active');
// deactivate the previously-active element (even if it was the clicked one => toggle)
if (active) active.classList.remove('active');
}
document.getElementById("techBio").addEventListener("click",activate);
document.getElementById("techCart").addEventListener("click",activate);
document.getElementById("techChem").addEventListener("click",activate);
h4 {
border: 1px solid black;
border-radius: 8px;
padding: 10px 2px 10px 2px;
margin: 20px 20px 0px 20px;
background-color: #F0F0F0;
border-color: #F8F8F8;
color: #505050;
cursor: pointer;
}
.active {
background-color: #99E6FF;
}
<div id="pTwoRowOne">
<div class="row">
<div class="col-md-4 row row-centered">
<h4 id="techBio" class="test">Biology</h4>
</div>
<div class="col-md-4 row row-centered">
<h4 id="techCart" class="test">Cartography</h4>
</div>
<div class="col-md-4 row row-centered">
<h4 id="techChem" class="test">Chemistry</h4>
</div>
</div>
</div>
Another similar yet simpler way to do it: jsBin ;)
var H4 = document.getElementsByClassName("test"), act;
[].forEach.call(H4, function(el){
el.addEventListener("click", function(){
if(act) act.classList.remove("active");
return (this.classList.toggle("active"), act=this);
});
});
You can do something like this:
[].slice.call(document.querySelectorAll(".test")).forEach(function(element) {
element.addEventListener('click', function(event) {
if (activeElement = document.querySelector(".test.active")) {
activeElement.classList.remove("active");
};
event.target.classList.add('active');
});
});
Basically, first we remove the active class from the active element, then we add it to the target.
JSBin

Edit link on div mouseover

On facebook for example - when you put your mouseover a news item, a remove button appears. How can I go about making this happen?
Thanks,
Elliot
Modern Browsers
In modern browsers, you can leverage the :hover pseudo class in our selector. As an example, consider the following markup:
<div class="item">
<p>This is a long string of text</p>
<div class="adminControls">
Delete Item
</div>
</div>
By default, we would want the .adminControls to be hidden. They should, however, become visible once the user has hovered the .item element:
.item .adminControls {
display: none;
}
.item:hover .adminControls {
display: block;
}
JavaScript and jQuery
If you're using jQuery, you can accomplish this rather easily using the $.hover() method. If you're using Prototype, you can get the protoHover plugin to achieve the same result, or view this blog post.
$("div.item").hover(
function () { $(this).find(".adminControls").show(); },
function () { $(this).find(".adminControls").hide(); }
);
That would accomplish the show/hide effect for the following:
<div class="item">
<p>This is a long string of text</p>
<div class="adminControls">
Delete Item
</div>
</div>
<div class="item">
<p>This is a long string of text</p>
<div class="adminControls">
Delete Item
</div>
</div>
<div class="item">
<p>This is a long string of text</p>
<div class="adminControls">
Delete Item
</div>
</div>
If you don't need to support IE6, you can use the :hover pseudoclass like so:
CSS:
.link { display: none; }
.item:hover > .link { display: inline; }
HTML:
<div class="item">
Remove
Lorem Ipsum...
</div>
Position the link as you'd like it to appear on hover, then hide it with JavaScript and use the onmouseover event to show it. (i.e., it's display: none; and then turns to display: block; when the onmouseover event is triggered).
Something like this:
window.onload = function(){
document.getElementById('mylink').style.display = 'none';
document.getElementById('mydiv').onmouseover = function(){
document.getElementById('mylink').style.display = 'block';
}
}
You need to write a Javascript function that manipulates the DOM and you need to associate the OnMouseOver attribute of your HTML element with that function. For example, on my home page a picture of my face changes every time the mouse rolls over it. The Javascript function is defined in the HTML page itself.
<script type="text/javascript">
<!--
faceCnt = 7;
var faces = new Array( faceCnt );
var faceDates = new Array( "1982", "1986", "1991", "1999", "2004", "2006", "2009" );
var faceIdx = 7; /* So that first change is to earliest one. */
for( var idx = 0 ; idx < faceCnt ; idx++ )
(faces[idx] = new Image(150, 116)).src = "david/david" + (idx + 1) + ".jpg";
function nextFace( ref )
{
faceIdx = faceIdx >= faceCnt - 1 ? 0 : faceIdx + 1;
ref.src = faces[ faceIdx ].src;
ref.title = "David-" + faceDates[ faceIdx ];
}
//-->
</script>
<img id="myface" src="david/david7.jpg" alt="david" title="David-2009"
width="150" height="116"
style="margin: 0 0 5px 15px; /* -10px -5px 10px 10px; */
padding: 0;
border: solid black;
border-width: 1px;
float: right;"
onMouseOver="nextFace( this )"
onClick="nextFace( this )" >

Categories

Resources