I have a list of 4 boxes, each have two sections .content-primary-wrapper and .content-secondary-wrapper, inside both these sections is a div called .content-inner. I am running a conditional based on the heights of the content-inner classes to decide which one get's a border-class addd to it.
As I have it now, the function runs, then applies the results to all of the classes, how can I get it to apply it on an element basis? I am trying to get it so it works like this:
Run function, determine heights of first element
determine heights of first element
Apply border class to this element only
Rinse and repeat for the other 3 objects
Here is my script I am using, any ideas how I could loop through these?
var primary_height = $('.content-primary-wrapper .content-inner').height();
var secondary_height = $('.content-secondary-wrapper .content-inner').height();
if ( primary_height >= secondary_height ){
$(this).find('.content-primary-wrapper .content-inner').addClass('add-border-right');
} else {
$(this).find('.content-secondary-wrapper .content-inner').addClass('add-border-left');
}
Is this what you're going for? Loop through all of your boxes, find the .content-inners in each one, and apply your class.
$(".box").each(function() {
var $pri = $(this).find(".content-primary-wrapper .content-inner"),
$sec = $(this).find(".content-secondary-wrapper .content-inner");
if ($pri.height() >= $sec.height()) {
$pri.addClass("add-border-right");
} else {
$sec.addClass("add-border-left");
}
});
.box {
float: left;
clear: both;
}
.add-border-left {
border-left: 1px solid red;
}
.add-border-right {
border-right: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">
<div class="content-primary-wrapper">
<div class="content-inner">two<br>lines</div>
</div>
<div class="content-secondary-wrapper">
<div class="content-inner">one</div>
</div>
</div>
<div class="box">
<div class="content-primary-wrapper">
<div class="content-inner">one</div>
</div>
<div class="content-secondary-wrapper">
<div class="content-inner">two<br>lines</div>
</div>
</div>
There are multiple ways you could do this. I would probably run a selector to get the elements that contain the four boxes, then run localized queries for the primary and secondary wrappers on them, like so:
$('.box-container').each(function(index, container) {
var primary_height = $('.content-primary-wrapper .content-inner', container).height();
var secondary_height = $('.content-secondary-wrapper .content-inner', container).height();
// ...
}
Alternatively, if you're sure that they're always going to be paired like this, you could simply do something like:
var primary_elements = $('.content-primary-wrapper .content-inner');
var secondary_elements = $('.content-secondary-wrapper .content-inner');
var i;
for (i = 0; i < primary_elements.length; ++i) {
var primary_height = $(primary_elements[i]).height();
var secondary_height = $(secondary_elements[i]).height();
// ...
}
This version seems a little less robust to me, just in case you start removing one or the other element at some point and they're no longer always paired in the way that this assumes.
Related
I have an image (SVG) of a human body. I would like to use JavaScript so that when I click a particular area (say, the lower leg) then all of the elements with the class "lower-leg" (even if not clicked) have their color changed -- this makes it much easier for the user.
Here is the JavaScript I currently have:
function changeclassstyle() {
var c = document.getElementsByClassName("lower-leg");
for (var i=0; i<c.length; i++) {
c[i].style.fill = "red";
}
}
The problem with this code is that it is only generalized for "lower-leg". I may have over a dozen classes I would like this to work for and don't think it is efficient to write 12 functions with the only change being the class name. Is there a way to grab what class was selected and then input that in the function?
--
Additionally, I would love to figure out how, once that section of the body is selected, I can store the class name. I would, in the end, want to store the selection, along with other inputted information in a database. But, this may be for a future question unless someone can help!
Here's how I would do it (tested on a couple of div's).
What we're doing is passing the event object to the event handler (your changeclassstyle() function). It then uses the class of the clicked-on item (the event target's class) and changes everything else on that page with that same class name to use your new desired CSS style.
function changeclassstyle(e) {
// Get all items that have the same class as the item that was clicked
var limbs = document.getElementsByClassName(e.target.className); // for div's and the like
// var limbs = document.getElementsByClassName(e.target.className.baseVal); // turns out this is needed for SVG items
// "limbs" is an HTMLCollection, not an array, so functions like .foreach won't work; C-style for-loops or modern for/let/of loops are better
for (let item of limbs) {
item.style.backgroundColor = 'red';
// item.style.fill = 'red'; // This is probably what you need for your SVG items
}
// You could still use your C-style for loop if needed/wanted
/*
for (var i=0; i<limbs.length; i++) {
limbs[i].style.fill = "red";
}
*/
}
The onchange call looks like this (using my div as the example):
<div class="upper-arm" onclick="changeclassstyle(event)">
</div>
<div class="lower-leg" onclick="changeclassstyle(event)">
</div>
The whole example with simple div's.
<html>
<head><title>stuff</title></head>
<body>
<script type="text/javascript">
function changeclassstyle(e) {
// For debugging. You may want to expand 'e' here in your browser's debug tools if you're not seeing the values you need/want
console.log(e)
var limbs = document.getElementsByClassName(e.target.className.baseVal);
for (let item of limbs) {
item.style.backgroundColor = 'red';
}
}
</script>
<style type="text/css">
div {
height: 100px;
width: 100px;
background-color: 'white';
border: 1px solid black;
}
</style>
<div class="upper-arm" onclick="changeclassstyle(event)">
</div>
<div class="upper-arm" onclick="changeclassstyle(event)">
</div>
<div class="upper-arm" onclick="changeclassstyle(event)">
</div>
<div class="lower-leg" onclick="changeclassstyle(event)">
</div>
<div class="lower-leg" onclick="changeclassstyle(event)">
</div>
<div class="lower-leg" onclick="changeclassstyle(event)">
</div>
</body>
</html>
You can use parameters in function where you pass class and color like below
function changeStyle(cls,clr) {
let elems = document.getElementsByClassName(cls);
if(!elems) return;
for (let elem of elems) {
elem.style.color = clr;
}
}
As per the iteration of many classes like i said you can store classes in array and iterate each of them.
let classes = ['one','two','three','four'];
classes.forEach(function (cls) {
changeStyle(cls,"red");
});
You can play with fiddle here if you want to test/experiment: https://jsfiddle.net/thrL5uqw/8/
Note: Change style property as you wish, For now i have used color for demo
I'm a bit late to the party, but here's my take on the problem.
Like the others told you, you'll need to use an additional parameter to your function to specify the class you want to modify your elements (or try to figure out the class from the clicked element), therefore you should have something like that:
/**
* This function will handle the click event on one of the part of the SVG.
* #param {string} lClass This the class of the element to modify
*/
function handleClick(lClass) {
for (let e of document.getElementsByClassName(lClass)) {
// Here you can do all the changes you need on the SVG element.
e.style.fill = "red";
}
}
And when it comes to the event binding, you could do like the other suggested and add the onclick event binding propery on the HTML Element, or you could bind it in you JS with the addEventListener function (that way you don't have to repeat the onclick property on each of your SVG elements).
// For each element of all the listed class, bind the "click" event to the handleClick function
const listenClass = [/*List of your classes*/];
for (let l of listenClass) {
for (let e of document.getElementsByClassName(l)) {
e.addEventListener('click', handleClick.bind(this, l));
}
}
Demo: https://plnkr.co/edit/gay2yBaVi5QD868fsTa6?p=preview
I hope it helped.
I have this code
The problem is I need to toggle class on click. I have classes
.col
.col-1 / .col-2 / col-3 etc.
and I need to apply on click to the right .col-1 / col-2 an expand class, so it would like
.col .col-1 .col-1--expand
.col .col-2 .col-2--expand
Before I had this on hover in CSS and it works, but make it on click is little problematic. I searched whole day Javascript and jQuery cases, but I haven't found any right solution to it.
What I learned, I must use forEach function in Javascript, but a solution in jQuery is also what I want.
I tried something like this on my project, but I'm still bad at Javascript :(
if (document.querySelector('.slider__col')) {
const expandElement = element.querySelectorAll('.slider__col')
expandElement.forEach(element => {
element.addEventListener('click', function() {
element.classList.toggle("");
})
})
You can use a regular expression to match element classes and toggle the expand class on that element when clicked.
var matched = this.className.match(/col-\d{1,2}/);
This will find any classes in your element's class attribute that contains col- followed by any numbers up to two digits so you can cater for 1-99.
matched.length && (matched = matched.pop())
.match() returns an array of matches so you can determine if any matches were found and pop the first match off of the array.
var expandClass = matched + '--expand';
Because you're matching, for example, col-1 you can use this string and append --expand to make col-1--expand.
$(this).toggleClass(expandClass);
You can use jQuery's toggleClass to add/remove the expandClass depending on the class's presence. See col-3 for demonstration.
$(document).on('click', '.col', function () {
var matched = this.className.match(/col-\d{1,2}/);
if (matched.length && (matched = matched.pop())) {
var expandClass = matched + '--expand';
$(this).toggleClass(expandClass);
}
});
.col {
background-color: blue;
color: white;
padding: .25rem 1rem;
margin: .25rem 0;
}
.col-1--expand,
.col-2--expand,
.col-3--expand,
.col-4--expand,
.col-5--expand,
.col-6--expand {
background-color: green;
padding-top: 1rem;
padding-bottom: 1rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="grid">
<div class="col col-1">1</div>
<div class="col col-2">2</div>
<div class="col col-3 col-3--expand">3</div>
<div class="col col-4">4</div>
<div class="col col-5">5</div>
<div class="col col-6">6</div>
</div>
Welcome to StackOverflow! Since you want a solution in jQuery, let me give you some guidance.
1. The forEach function is in jQuery available as the
.each() method. Making your code:
// Select your classes, for each of them run a function
$('.col-1').each(function() { });
2. To make something happen on a click, jQuery has a .click() method available, it will call a function on click. Making your code:
$('.col-1').each(function() {
// Click method:
$(this).click(function() { } );
});
// Or just do:
$('.col-1').click(function() { });
jQuery does not need a loop and can bind the click method to all classes by itself. There are cases where it still might be useful, but let's keep it basic for now and get your code working!
3. Adding the new CSS class. In jQuery there are many methods you can use for it. In this case you are probably looking for the .toggleClass() method. Other useful ones might me .addClass() and .removeClass(). Making your code:
$('.col-1').click(function() {
$(this).toggleClass("col-1--expand");
});
// Or just add it:
$('.col-1').click(function() {
$(this).addClass("col-1--expand");
});
Done, repeat for other classes where you want to do some magic. Next time try spending a day on the jQuery API Documentation. All the methods are there, with great examples included! Best of luck with it.
Let's say I have a simple HTML markup with three elements and a javascript loop looking through all of them. What I need to do is to select the last one of those items.
This pile of code will run a loop, select all elements with some_div class, and paste some text inside them...
What if I only wanted the last item on the list to be selected and changed?
Is there a way for me to only select the last item from the loop and then do some operations like adding a specific class to this exact element?
var elements = document.getElementsByClassName('some_div');
for (var i=0; i<elements.length; i++) {
elements[i].innerHTML = 'hello';
}
.some_div {
height: 30px;
width: 100px;
border-bottom: solid 2px black;
}
<body>
<div class="some_div"></div>
<div class="some_div"></div>
<div class="some_div"></div>
</body>
Selecting the last match for a class (e.g., with a CSS selector) is awkward¹, but you can easily access the last match:
var elements = document.getElementsByClassName('some_div');
var last = elements[elements.length - 1];
if (last) {
last.innerHTML = 'hello';
}
Live Example:
var elements = document.getElementsByClassName('some_div');
var last = elements[elements.length - 1];
if (last) {
last.innerHTML = 'hello';
}
.some_div {
height: 30px;
width: 100px;
border-bottom: solid 2px black;
}
<body>
<div class="some_div"></div>
<div class="some_div"></div>
<div class="some_div"></div>
</body>
¹ (or impossible? :nth-last-of-type applies to element type, not class...)
since elements is an array-like object, you can easily index the last item
const elements = document.getElementsByClassName('some_div');
if(elements.length > 0){
const lastElement = elements[elements.length-1]
}
I have a jQuery project where I'm looping through a list of elements that all have the same class. What I need is for the 1st two elements class to be removed. Therefore I'm using the .removeClass() method. However, I don't know how to use that method and only remove the 1st two. It's moving all of them. Can someone help me without changing the direction of my code.
function putSiblingsInTableForEachH2() {
// line above sets function that will ultimately store siblings of each h2.toggler into a HTML table
var togglerHeaders = $("h2.toggler");
// line above sets variable togglerHeaders to all h2 elements with a class of ".toggler"
for (i = 0; i < togglerHeaders.length; i++) {
// line above: for loop that loops through array "togglerHeaders"
var currentH2Element = togglerHeaders[i];
// line above sets variable currentH2Element to togglerHeaders at position i
if (currentH2Element == togglerHeaders[0] || togglerHeaders[1]) {
$("h2").removeClass("toggler");
}
var siblingsofH2 = $(currentH2Element).nextUntil("h2.toggler");
// line above access siblings that are in h2.toggler element
// line says: set variable "siblingsofH2" to the current h2.toggler element you're on actual sibling elements but only siblings that are in between current element and next element that is "h2.toggler"
$(siblingsofH2).wrapAll("<table></table>");
// line above says: after correct sibling elements are stored to variable siblingsofH2 wrap elements in HTML table
} // line ends for loop
} // line ends function
putSiblingsInTableForEachH2();
// line above actually runs function
Of course $("h2").removeClass("toggler"); will remove class from all, because it is referring to all.
I slightly edited your lines:
if (i < 2) {
$(currentH2Element).removeClass("toggler");
}
Plain JS .querySelectorAll with :nth-child formula
var firstTwo = document.querySelectorAll(".my-class:nth-child(-n+2)");
This is what I came up with.
var putThingsInTable = query => {
var matches = document.querySelectorAll(query);
if(!matches) return;
var table = document.createElement('table')
table.appendChild(document.createElement('tr'))
var i = 0;
var toAdd = [];
matches.forEach(match => {
if(i > 1){
toAdd.push(match);
}
i++
});
toAdd.forEach(element => {
var td = document.createElement('td');
td.appendChild(element);
table.children[0].appendChild(td)
});
return table;
}
document.body.appendChild(putThingsInTable('h2.toggler'))
table, th, td {
border: 1px solid black;
}
<h2 class="toggler">a</h2>
<h2 class="toggler">a</h2>
<h2 class="toggler">a</h2>
<h2 class="toggler">c</h2>
<h2 class="toggler">c</h2>
<h2 class="toggler">w</h2>
<h2 class="toggler">w</h2>
<h2 class="toggler">w</h2>
<h2 class="toggler">w</h2>
Answer
This is the line of jQuery you are looking for ...
$("h2.toggler:gt(1)")
Explanation
:gt(1) Will select all elements at an index greater than 1 within the matched set
See ... https://api.jquery.com/gt-selector/
Example
For full example see ...
https://codepen.io/stephanieschellin/pen/MPdWVw
or ...
$('h2.toggler:gt(1)').each(function(e) {
$(this).nextUntil('h2').wrapAll('<table></table>')
})
table {
color: blue;
border: solid 3px black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2 class="toggler">one</h2>
<span>one</span>
<span>one</span>
<h2 class="toggler">two</h2>
<span>two</span>
<span>two</span>
<h2 class="toggler">three</h2>
<span>three</span>
<span>three</span>
<span>three</span>
<h2 class="toggler">four</h2><span>four</span>
<span>four</span>
<span>four</span>
<h2 class="toggler">five</h2>
<span>five</span>
<span>five</span>
<span>five</span>
<span>five</span>
<h2 class="toggler">six</h2>
<span>six</span>
<span>six</span>
I am trying to make webpage where there is a div in the center which is being changed, instead of going to different pages.
Ultimately, I would like to have the new div, when clicking on an arrow, to flow from right or left in to the center. But first I would like to make the divs appear and disappear when clicking on the arrows but unfortunately this doesn't work.
This is my javascript:
<script>
function changeToHome() {
document.getElementById("mainmain").style.display="block";
document.getElementById("mainmain2").style.display="none";
document.getElementById("mainmain3").style.display="none";
document.getElementById("mainmain4").style.display="none";
}
function changeToStudy() {
document.getElementById("mainmain").style.display="none";
document.getElementById("mainmain2").style.display="block";
document.getElementById("mainmain3").style.display="none";
document.getElementById("mainmain4").style.display="none";
}
function changeToJob() {
document.getElementById("mainmain").style.display="none";
document.getElementById("mainmain2").style.display="none";
document.getElementById("mainmain3").style.display="block";
document.getElementById("mainmain4").style.display="none";
}
function changeToContact() {
document.getElementById("mainmain").style.display="none";
document.getElementById("mainmain2").style.display="none";
document.getElementById("mainmain3").style.display="none";
document.getElementById("mainmain4").style.display="block";
}
function changePageRight() {
var displayValue5 = document.getElementById('mainmain').style.display;
var displayValue5 = document.getElementById('mainmain2').style.display;
var displayValue6 = document.getElementById('mainmain3').style.display;
var displayValue7 = document.getElementById('mainmain4').style.display;
if (document.getElementById('mainmain').style.display == "block") {
document.getElementById("mainmain").style.display="none";
document.getElementById("mainmain2").style.display="block";
}
else if (document.getElementById('mainmain2').style.display == "block") {
document.getElementById("mainmain2").style.display="none";
document.getElementById("mainmain3").style.display="block";
}
else if (document.getElementById('mainmain3').style.display == "block") {
document.getElementById("mainmain3").style.display="none";
document.getElementById("mainmain4").style.display="block";
}
else if (displayValue8 == block) {}
}
function changePageLeft() {
var displayValue = document.getElementById('mainmain').style.display;
var displayValue2 = document.getElementById('mainmain2').style.display;
var displayValue3 = document.getElementById('mainmain3').style.display;
var displayValue4 = document.getElementById('mainmain4').style.display;
if (displayValue == "block") { }
else if (displayValue2 == "block") {
document.getElementById("mainmain").style.display="block";
document.getElementById("mainmain2").style.display="none";
}
else if (displayValue3 == "block") {
document.getElementById("mainmain2").style.display="block";
document.getElementById("mainmain3").style.display="none";
}
else if (displayValue4 === "block") {
document.getElementById("mainmain3").style.display="block";
document.getElementById("mainmain4").style.display="none";
}
}
</script>
Now I have a few divs that look like this:
<div id="mainmain4">
<img style="width:400px;height:327px;margin-left:auto;margin-right:auto;display:block;" src="Untitled-22.png" />
<h2> My name </h2>
<p>Hi,</p>
<p>Some text</p>
</div>
With these css atributes:
#mainmain {
float: left;
width: 575px;
display: block;
position: relative;
}
And all other divs with display: none; so I can change this to block and the one that was block to none.
For some reason, after when I click on one button of the menu, which activates a changeToX() function, the arrows work great. But before that, when you first go to the website, it doesn't.
Can someone explain me what I do wrong?
You don't tell the browser which divs shall be displayed on load. You can use theonloadevent for this:
<body onload="changeToHome()">
One additional hint: you maybe don't want to use inline JavaScript and CSS.
jQuery is as this simple:
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
toggle!
<div id="mainmain">test text</div>
<script>
// you need this, only apply javascript when all html (dom) is loaded:
$(document).ready(function() {
$('.toggle-container').on('click', function(e) {
e.preventDefault(); // this prevents the real href to '#'
// .toggle() is like "on / off" switch for hiding and showing a container
$($(this).data('container')).toggle();
});
});
</script>
This function can be reused, because it is based on classes instead of id's.
Check this JSFiddle: http://jsfiddle.net/r8L6xg15/
Maybe this is of some use. I've tried to make a page control-like behaviour. You can select any container div and put elements in there that have the class 'page'. The JavaScript code will let you navigate those with buttons.
You can make it more fancy by adding the buttons through JavaScript. What you then have is basically a list of pages which are normally displayed as regular divs, but when the script kicks in, it changes them to a page control.
You can call this for any parent element, and in that sense it behaves a bit like a jQuery plugin. It is all native JavaScript, though. And not too much code, I hope. Like you said, I think it's good to learn JavaScript at first. It is very powerful by itself, and it's becoming increasingly powerful. jQuery adds a lot of convenience functions and provides fallbacks in case browser don't support certain features, or when implementations differ. But for many tasks, bare JavaScript will do just fine, and it certainly can't hurt to know your way around it.
Press the 'Run this snippet' button at the bottom to see it in action.
function Pages(element)
{
// Some initialization
var activePage;
// Find all pages within this element.
var pages = document.querySelectorAll('.page');
var maxPage = pages.length - 1;
// Function to toggle the active page.
var setPage = function(index)
{
activePage = index;
for (p = 0; p <= maxPage; p++)
{
if (p == activePage)
pages[p].className = 'page active';
else
pages[p].className = 'page inactive';
}
}
// Select the first page by default.
setPage(0);
// Handler for 'previous'
element.querySelector('.prev').onclick = function()
{
if (activePage == 0)
return;
setPage(activePage - 1);
}
// Handler for 'next'
element.querySelector('.next').onclick = function()
{
if (activePage == maxPage)
return;
setPage(activePage + 1);
}
// Add a class to the element itself. This way, you can already change CSS styling
// depending on whether this code is loaded or not. So in case of an error, the
// divs are just all show underneath each other, and the nav buttons are hidden.
element.className = element.className + ' js';
}
Pages(document.querySelector('.pages'));
.pages .page {
display: block;
padding: 40px;
border: 1px solid blue;
}
.pages .page.inactive {
display: none;
}
.pages .nav {
display: none;
}
.pages.js .nav {
display: inline-block;
}
<div class="pages">
<button class="nav prev">Last</button>
<button class="nav next">Next</button>
<div class="page">Page 1 - Introduction and other blah</div>
<div class="page">Page 2 - Who am I? Who are you? Who is Dr Who?</div>
<div class="page">Page 3 - Overview of our products
<ul><li>Foo</li><li>Bar</li><li>Bar Pro</li></ul>
</div>
<div class="page">Page 4 - FAQ</div>
<div class="page">Page 5 - Contact information</div>
</div>
To dos to make this a little more professional:
Add the navigation through JavaScript
Disable the buttons when first/last page has been reached
Support navigation by keys too (or even swipe!)
Some CSS transform (fade or moving) when toggling between pages
Smarter adding and removing of classes. Now I just set className, which sucks if someone would like to add classes themselves. jQuery has addClass and removeClass for this, which is helpful. there are also stand-alone libraries that help you with this.
Visible indication of pages, maybe with tabs at the top?