pick certain amount of child elements from the dom - javascript

i have for example 15 div tags with a certain class name in a page
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
and i can select them using jquery
var targetDivs = $(' .className ');
it is going to return 15 div tags in this case but i want to randomly pick only 9 of them and store them in another variable

You could use Jquery Each and build a unique and random element array.
You could then loop out on your element array to place the elements where you want this randomization to occur.
var divs = [];
var indexs = [];
while(indexs.length < 9){
var num = Math.floor(Math.random() * 9) + 1;
indexs.push(num);
indexs = $.unique(indexs);
}
$('.className').each(function(index, element){
if(indexs[index]){
divs.push($('.className').eq(indexs[index]));
}
});
console.log(divs);

You just need to generate a random number and then use that number as the basis for looping:
var targetDivs = document.querySelectorAll('.className');
var randomAmount = prompt("What is the upper limit for a random number you want?");
var randomNum = Math.floor(Math.random() * randomAmount);
console.log("Random number is: " + randomNum);
for(var i = 0; i < randomNum; ++i){
var randomNode = Math.floor(Math.random() * targetDivs.length);
console.log("Result includes: " + targetDivs[randomNode].textContent);
}
<div class="className">CONTENT 1</div>
<div class="className">CONTENT 2</div>
<div class="className">CONTENT 3</div>
<div class="className">CONTENT 4</div>
<div class="className">CONTENT 5</div>
<div class="className">CONTENT 6</div>
<div class="className">CONTENT 7</div>
<div class="className">CONTENT 8</div>
<div class="className">CONTENT 9</div>
<div class="className">CONTENT 10</div>
<div class="className">CONTENT 11</div>
<div class="className">CONTENT 12</div>
<div class="className">CONTENT 13</div>
<div class="className">CONTENT 14</div>
<div class="className">CONTENT 15</div>

One approach I'd suggest is the use of a simple plugin:
(function($) {
// naming the new plugin ('getRandom'):
$.fn.getRandom = function(n) {
// creating an Array by passing the jQuery collection
// the 'this' passed to the function to the get()
// method, which takes the passed-in collection
// and returns a jQuery Array:
var collection = this.get(),
// creating an Array, using an Array-literal:
result = [],
// initialising a variable for use, later:
rand;
// converting the passed-in argument, 'n', into a
// base-10 ('10') Number, using parseInt() (this
// does no harm if 'n' is already a Number, but
// ensures that, if a String is passed in ('3' for
// example) we get a Number back out:
n = parseInt(n, 10);
// while n is still truthy (so non-zero):
while (n) {
// we generate a random number in the range of
// 0 to the length of the collection Array:
rand = Math.floor(Math.random() * collection.length);
// we use the random number as an index, and
// push the Array-element at that index in the
// collection Array into the result Array:
result.push(collection[rand]);
// we then remove the element at that index from the
// collection Array, passing in the same index ('rand')
// and deleting one element ('1'):
collection.splice(rand, 1);
// decrement the n variable:
n--;
}
// convert the result Array of elements back into
// object, and return that object to the calling
// context for chaining:
return $(result);
}
})(jQuery);
(function($) {
$.fn.getRandom = function(n) {
var collection = this.get(),
result = [],
rand;
n = parseInt(n, 10);
while (n) {
rand = Math.floor(Math.random() * collection.length);
result.push(collection[rand]);
collection.splice(rand, 1);
n--;
}
return $(result);
}
})(jQuery);
$('.className').getRandom(10).css({
'opacity': '0.2'
})
.className {
display: inline-block;
width: 3em;
height: 3em;
box-sizing: border-box;
border: 2px solid #000;
text-align: center;
overflow: hidden;
counter-increment: boxCounter;
position: relative;
}
.className::after {
content: counter(boxCounter, decimal-leading-zero);
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: #fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
JS Fiddle demo.
As most of the jQuery plugin above is written in plain JavaScript this is, of course, similarly easily-possible in plain JavaScript, albeit as a function, rather than a method or prototype-extension (although, if you wish to do it that way, it remains easily-possible to do so, albeit not necessarily advised):
function getRandomFrom(haystack, n) {
// ensuring that we have an Array, assuming we're
// passed an Array-like Object (such as a NodeList,
// HTMLCollection or, even, an Array):
haystack = Array.from(haystack);
// ensuring that the variable n is a Number, using
// parseInt():
n = parseInt(n, 10);
// creating an empty Array:
var result = [],
// initialising a variable for later use:
rand;
// while n is truthy (non-zero):
while (n) {
// we generate a random number between 0 and
// the Array-length:
rand = Math.floor(Math.random() * haystack.length);
// we use the random number as an index for the Array,
// and push the Array-element held at that index to the
// result Array:
result.push(haystack[rand]);
// we remove that Array-element from the Array, using
// Array.prototype.splice():
haystack.splice(rand, 1);
// decrement n, to ensure we don't have an infinite
// while loop:
n--;
}
// return the result Array to the calling context:
return result;
}
function getRandomFrom(haystack, n) {
haystack = Array.from(haystack);
n = parseInt(n, 10);
var result = [],
rand;
while (n) {
rand = Math.floor(Math.random() * haystack.length);
result.push(haystack[rand]);
haystack.splice(rand, 1);
n--;
}
return result;
}
var elems = document.querySelectorAll('.className');
getRandomFrom(elems, 5).forEach(el => el.classList.add('selected'));
.className {
display: inline-block;
width: 3em;
height: 3em;
box-sizing: border-box;
border: 2px solid #000;
text-align: center;
overflow: hidden;
counter-increment: boxCounter;
position: relative;
}
.className::after {
content: counter(boxCounter, decimal-leading-zero);
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: #fff;
}
.className.selected {
opacity: 0.25;
border-color: red;
}
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
<div class="className">CONTENT</div>
References:
JavaScript:
Array.prototype.splice().
Array.prototype.splice().
Array.prototype.push().
Array.prototype.splice().
Arrow functions.
Element.classList.
Math.floor().
Math.random().
parseInt().
jQuery:
css().
Bibliography:
"How to Create a Basic Plugin."

Example below using ES6 Map:
let results = new Map();
for(let i = 0; i < 9; i++) {
let index= null;
while(index=== null || results.has(index)) {
index= Math.floor(Math.random() * 9);
}
results.set(index, document.querySelectorAll('.className')[index]);
}
for (let result of results.values()) {
console.log(result.textContent)
}
<div class="className">CONTENT 1</div>
<div class="className">CONTENT 2</div>
<div class="className">CONTENT 3</div>
<div class="className">CONTENT 4</div>
<div class="className">CONTENT 5</div>
<div class="className">CONTENT 6</div>
<div class="className">CONTENT 7</div>
<div class="className">CONTENT 8</div>
<div class="className">CONTENT 9</div>
<div class="className">CONTENT 10</div>
<div class="className">CONTENT 11</div>
<div class="className">CONTENT 12</div>
<div class="className">CONTENT 13</div>
<div class="className">CONTENT 14</div>
<div class="className">CONTENT 15</div>

Related

How can I loop through indexes that rely on multiple functions?

I am using two types of elements, .element and .summary. The index of both classes correspond to each other, so when a user has a mouseover event on .element, a class should be added to its corresponding .summary. Similarly, that same class should be removed on mouseout.
In other words, I'm looking to have the .styling class only applied to .summary when .element is on mouseover
Without declaring so many variables, I was wondering the most efficient way to loop through these elements.
var abc = document.getElementsByClassName("element");
var xyz = document.getElementsByClassName("summary");
for (let i = 1; i < xyz.length; i++) {
abc[i].addEventListener("mouseover", movein(i), false);
abc[i].addEventListener("mouseout", moveout(i), false);
}
function movein(i) {
xyz[i].classList.add("styling");
}
function moveout(i) {
xyz[i].classList.remove("styling");
}
.element {
cursor: pointer;
}
.styling {
background: red;
}
<div class="element">Element 1</div>
<div class="element">Element 2</div>
<div class="element">Element 3</div>
<div class="summary">Summary 1</div>
<div class="summary">Summary 2</div>
<div class="summary">Summary 3</div>
From what I can tell, these functions run but it doesn't work on mouseover.
You don't actually have to loop, in fact it's probably best you don't. If you have containers for each section of your HTML: elements, and summaries, it's much more efficient to use event delegation to catch element events as they bubble up the DOM, and use one handler to decide how to style your summaries depending on their data attributes.
// Cache the containers
const elements = document.querySelector('#elements');
const summaries = document.querySelector('#summaries');
// Add listeners to the containers
elements.addEventListener('mouseover', handleMouse, false);
elements.addEventListener('mouseout', handleMouse, false);
function handleMouse(e) {
// Destructure the type and id from the element
const { type, target: { dataset: { id } } } = e;
// Find the corresponding summary - this uses
// a template literal to create the query
const summary = summaries.querySelector(`[data-id="${id}"]`);
// And then, depending on the event type, add or remove the style
if (type === 'mouseover') {
summary.classList.add("styling");
} else {
summary.classList.remove("styling");
}
}
.element { cursor: pointer; }
.styling { background: red; }
<div id="elements">
<div data-id="1" class="element">Element 1</div>
<div data-id="2" class="element">Element 2</div>
<div data-id="3" class="element">Element 3</div>
</div>
<div id="summaries">
<div data-id="1" class="summary">Summary 1</div>
<div data-id="2" class="summary">Summary 2</div>
<div data-id="3" class="summary">Summary 3</div>
</div>
Additional documentation
Destructuring assignment
Template literals
Data attributes
Fixing your code to just refer to the functions (not call them) in addEventListener, to loop starting at 0 (not 1), and to use ids to get the corresponding elements...
There's nothing wrong with a short loop.
var abc = document.getElementsByClassName("element");
var xyz = document.getElementsByClassName("summary");
// fixed, was i=1
for (let i = 0; i < xyz.length; i++) {
// fixed, was movein(i), moveout(i)
abc[i].addEventListener("mouseover", movein, false);
abc[i].addEventListener("mouseout", moveout, false);
}
// these get events as params, and can use the event.target.id
// to distinguish which element was triggered
function movein(event) {
let id = event.target.id
xyz[id].classList.add("styling");
}
function moveout(event) {
let id = event.target.id
xyz[id].classList.remove("styling");
}
.element {
cursor: pointer;
}
.styling {
background: red;
}
<div class="element" id="0">Element 1</div>
<div class="element" id="1">Element 2</div>
<div class="element" id="2">Element 3</div>
<div class="summary">Summary 1</div>
<div class="summary">Summary 2</div>
<div class="summary">Summary 3</div>
You could do it like this, and not have to update your html. We programmatically set up an attribute so we can get it's index when we mouse over it. Then we use that index to find the associated summary. Note that you don't pass the i through the event listener - you test for the event.target and pick up that shiny new attribute with event.target.dataset per the code below.
Another bonus here is that we've combined the event listener logic which you can see makes sense. This answer leverages your existing structure, uses less code and is easy to understand.
var abc = document.getElementsByClassName("element");
var xyz = document.getElementsByClassName("summary");
for (let i = 0; i < xyz.length; i++) {
abc[i].setAttribute('data-index', i)
abc[i].addEventListener("mouseover", mousemove);
abc[i].addEventListener("mouseout", mousemove);
}
function mousemove(event) {
let element = xyz[event.target.dataset.index];
if (event.type == 'mouseover') element.classList.add("styling");
else element.classList.remove("styling");
}
.element {
cursor: pointer;
}
.styling {
background: red;
}
<div class="element">Element 1</div>
<div class="element">Element 2</div>
<div class="element">Element 3</div>
<div class="summary">Summary 1</div>
<div class="summary">Summary 2</div>
<div class="summary">Summary 3</div>

Equal height divs in different containers

So I am trying to set equal height for divs that are in different containers. But I am missing something and can't get it to work. Maybe you will spot the problem?
var howMany = $('.comparison-table__labels-wrap .equal-row').length;
for (var i=0; i<howMany; i++) {
var firstBlock = 'equal-row-' + i;
var firstHeight = $(firstBlock).height();
var secondBlock = '.equal-row-' + i + '-child';
var secondHeight = $(secondBlock).height();
if (firstHeight < secondHeight) {
$(firstBlock).css("height", secondHeight);
} else {
$(secondBlock).css("height", firstHeight);
}
}
.row {
border-color: #232323;
border-width: 1px;
border-style: solid;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container-1">
<div class="row equal-row-0">Row 0</div>
<div class="row equal-row-1">Row 1</div>
<div class="row equal-row-2">Row 2</div>
<div class="row equal-row-3">Row 3</div>
<div class="row equal-row-4">Row 4</div>
<div class="row equal-row-5">Row 5</div>
<div class="row equal-row-6">Row 6</div>
</div>
<div class="container-2">
<div class="row equal-row-0-child">Row 0</div>
<div class="row equal-row-1-child">Row 1</div>
<div class="row equal-row-2-child">Row 2</div>
<div class="row equal-row-3-child">Row 3</div>
<div class="row equal-row-4-child">Row 4</div>
<div class="row equal-row-5-child">Row 5</div>
<div class="row equal-row-6-child">Row 6</div>
</div>
funny example ;)
function equalizeHeights() {
const firstDivs = document.querySelectorAll(".first div")
const secondDivs = document.querySelectorAll(".second div")
const heights = []
for (let div of firstDivs) {
heights.push(div.clientHeight)
}
for (let i = 0; i < heights.length; i++) {
secondDivs[i].style.height = heights[i] + "px"
}
}
equalizeHeights()
function randomlyChangeHeight() {
const divs = document.querySelectorAll(".first div")
const randomNum = Math.floor(divs.length * Math.random())
const randomHeight = Math.floor(50 + 100 * Math.random())
divs[randomNum].style.height = randomHeight + "px"
}
setInterval(() => {
randomlyChangeHeight();
}, 500)
setTimeout(
() =>
setInterval(equalizeHeights, 250), 250)
.first div {
height: 50px;
}
div div {
transition: height 500ms;
border: 1px solid goldenrod;
text-align: center;
padding: 20px;
box-sizing: border-box;
}
.first,
.second {
width: 50%;
float: left;
}
.first div:nth-child(odd),
.second div:nth-child(even) {
background-color: mediumseagreen;
}
<div class="first">
<div>Row</div>
<div>Row</div>
<div>Row</div>
<div>Row</div>
<div>Row</div>
</div>
<div class="second">
<div>Row</div>
<div>Row</div>
<div>Row</div>
<div>Row</div>
<div>Row</div>
</div>
I think you need $('[class^="equal-row"]') to select all divs that you need. See this:
function setNewHeight() {
var howMany = $('[class^="equal-row"]').length;
//console.log(howMany);
for (var i = 0; i < howMany; i++) {
var firstBlock = '.equal-row-' + i;
var firstHeight = $(firstBlock).height();
//console.log(firstBlock, firstHeight);
var secondBlock = '.equal-row-' + i + '-child';
var secondHeight = $(secondBlock).height();
//console.log(secondBlock, secondHeight);
if (firstHeight < secondHeight) {
$(firstBlock).css("height", secondHeight);
} else {
$(secondBlock).css("height", firstHeight);
}
}
}
setNewHeight();
.container-1 div, .container-2 div{
border: 1px solid #ccc
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<div class="container-1">
<div class="container-1">
<div class="equal-row-0">Row 0
<br> test1
</div>
<div class="equal-row-1">Row 1</div>
<div class="equal-row-2">Row 2</div>
<div class="equal-row-3">Row 3</div>
<div class="equal-row-4">Row 4
<br>test2
</div>
<div class="equal-row-5">Row 5</div>
<div class="equal-row-6">Row 6</div>
</div>
<div class="container-2">
<div class="equal-row-0-child">Row 0</div>
<div class="equal-row-1-child">Row 1</div>
<div class="equal-row-2-child">Row 2</div>
<div class="equal-row-3-child">Row 3</div>
<div class="equal-row-4-child">Row 4</div>
<div class="equal-row-5-child">Row 5</div>
<div class="equal-row-6-child">Row 6
<br>test3
</div>
</div>
Its way better to use an abstract class in the elements. And you can do the number definition in a different attribute. This will make the implementation much easier. See the example bellow:
$('.equal-row').each(function () {
var number = $(this).attr('rel');
var parentHeight = $(this).height();
$('.equal-row-child[rel='+number+']').height(parentHeight)
});
.container-1 .equal-row[rel="0"] {
height: 30px;
}
.container-1 .equal-row[rel="1"] {
height: 45px;
}
.container-1 .equal-row[rel="2"] {
height: 15px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<div class="container-1">
<div rel="0" class="equal-row">Row 0</div>
<div rel="1"class="equal-row">Row 1</div>
<div rel="2" class="equal-row">Row 2</div>
</div>
<div class="container-2">
<div rel="0" class="equal-row-child">Row 0</div>
<div rel="1"class="equal-row-child">Row 1</div>
<div rel="2" class="equal-row-child">Row 2</div>
</div>
If you have any problems, let me now :)
So this works just fine:
(function(){
var howManyCols = $('.comparison-table__labels-wrap .equal-row').length;
for (var i=0; i<howManyCols; i++) {
var height1 = $('.equal-row-' + i).outerHeight();
var col1 = $('.equal-row-' + i);
var height2 = $('.equal-row-' + i + '-child').outerHeight();
var col2 = $('.equal-row-' + i + '-child');
if(height1 < height2) {
$(col1).css("height", height2);
} else {
$(col2).css("height", height1);
}
}
})();

Code only working in Firefox

The given code is only working in Firefox and not in any other browser.
I have given the Fiddle link for it.The code is working fine in Firefox and the functions are also working but it is not supported by any other browser.
The error shows is
Error due to long Script
Fiddle
Here is the code.
var $boxes;
$(document).ready(function() {
$boxes = $(".box");
setupColumns();
$(window).on("resize", setupColumns);
});
function setupColumns() {
var $columnwrapper = $("#columns");
var w = $("<div>").addClass("column").width();
var cnt = Math.floor($columnwrapper.width() / w);
var cols = [];
for (var i = 0; i < cnt; i++) {
var $col = $("<div>").addClass("column");
cols.push($col);
}
$columnwrapper.append(cols);
var cnt = 0;
$boxes.each(function() {
$(this).detach().appendTo(cols[cnt]);
cnt = (cnt + 1) % cols.length;
});
}
$(".box").click(function() {
if ($(this).height() != 100)
$(this).animate({
height: 100
}, 1000);
else
$(this).animate({
height: 150
}, 1000);
});
.column {
width: 114px;
float: left
}
.box {
height: 100px;
width: 100px;
border: 2px solid;
margin-bottom: 10px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="columns"></div>
<div class="box">HELLO WORLD 1</div>
<div class="box">HELLO WORLD 2</div>
<div class="box">HELLO WORLD 3</div>
<div class="box">HELLO WORLD 4</div>
<div class="box">HELLO WORLD 5</div>
<div class="box">HELLO WORLD 6</div>
<div class="box">HELLO WORLD 7</div>
<div class="box">HELLO WORLD 8</div>
<div class="box">HELLO WORLD 9</div>
<div class="box">HELLO WORLD 10</div>
The problem is due to following line:
var w = $("<div>").addClass("column").width();
Apart from Firefox, in other browsers its returning 0 which causes cnt to become Infinity. That's why you are getting a really long running script that's creating infinite divs and adding them to cols[]
Documentation for .width() says:
The value reported by .width() is not guaranteed to be accurate when
the element or its parent is hidden. To get an accurate value, ensure
the element is visible before using .width().
So what you will need to do is:
var $boxes;
$(document).ready(function() {
$boxes = $(".box");
setupColumns();
$(window).on("resize", setupColumns);
});
function setupColumns() {
var $columnwrapper = $("#columns");
//////////start change////////////
var dummy = $("<div>").addClass("column");
dummy.appendTo($columnwrapper); // add it to wrapper so that it gets displayed
var w = dummy.width(); // this now returns 114
dummy.remove(); // now that we have got the width, remove it
// just to be on safer side:
if(w == 0){
console.log("column width is 0.");
return;
}
//////////end change////////////
var cnt = Math.floor($columnwrapper.width() / w);
var cols = [];
for (var i = 0; i < cnt; i++) {
var $col = $("<div>").addClass("column");
cols.push($col);
}
$columnwrapper.append(cols);
var cnt = 0;
$boxes.each(function() {
$(this).detach().appendTo(cols[cnt]);
cnt = (cnt + 1) % cols.length;
});
}
$(".box").click(function() {
if ($(this).height() != 100)
$(this).animate({
height: 100
}, 1000);
else
$(this).animate({
height: 150
}, 1000);
});
.column {
width: 114px;
float: left
}
.box {
height: 100px;
width: 100px;
border: 2px solid;
margin-bottom: 10px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="columns"></div>
<div class="box">HELLO WORLD 1</div>
<div class="box">HELLO WORLD 2</div>
<div class="box">HELLO WORLD 3</div>
<div class="box">HELLO WORLD 4</div>
<div class="box">HELLO WORLD 5</div>
<div class="box">HELLO WORLD 6</div>
<div class="box">HELLO WORLD 7</div>
<div class="box">HELLO WORLD 8</div>
<div class="box">HELLO WORLD 9</div>
<div class="box">HELLO WORLD 10</div>
This is maybe because of cross-browser security concept by the modern browsers. If you are trying to run in Google Chrome. You might have to use the older version or install the plugin such as this:
https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en

Determine which div is in the middle of a div list

I have a div list that looks like this:
<div class="item"></div>
<div class="item"></div>
<div class="item"></div> <!--the middle one-->
<div class="item"></div>
<div class="item"></div>
I need to determine which div is in the middle of the list, please note that the div number is dynamic, depends on user's input. my final goal is to determine which divs are on the left and right side of the "middle div" then apply a class depends on its position.
The final result should look like this:
<div class="item left"></div>
<div class="item left"></div>
<div class="item center"></div> <!--the middle one-->
<div class="item right"></div>
<div class="item right"></div>
I was thinking to add a number identifier for each div and use median to determine the "middle div" but I'm not quite sure.
Perhaps there is a better approach for this problem using javascript, jquery or even pure css?
Update:
Additional information for handling even number:
in case the list has even number of child divs, it should divide it like this
<div class="item left"></div>
<div class="item left"></div>
<div class="item left"></div>
<div class="item right"></div>
<div class="item right"></div>
<div class="item right"></div>
in my problem, both Rory McCrossan and user3297291 works well. I added some modification to both of it for handling even numbers.
Rory McCrossan's (with JQuery):
var $items = $('.item');
var middleIndex = Math.floor($items.length / 2);
var hasMid = $items.length % 2;
console.log(middleIndex);
if(hasMid == 1){
$items.eq(middleIndex).addClass('middle')
.prevAll().addClass('left').end()
.nextAll().addClass('right');
}
if(hasMid == 0){
$items.eq(middleIndex).addClass('right')
.prevAll().addClass('left').end()
.nextAll().addClass('right');
}
user3297291's :
var setMidClasses = function (elementList, beforeMid, atMid, afterMid) {
var i = 0,
hasMid = elementList.length % 2,
mid = Math.floor(elementList.length / 2);
while (i < mid) {
elementList[i].classList.add(beforeMid);
i += 1;
}
if (hasMid == 1) {
elementList[i].classList.add(atMid);
i += 1;
}
while (i < elementList.length) {
elementList[i].classList.add(afterMid);
i += 1;
}
};
setMidClasses(document.querySelectorAll(".item"),
"left", "middle", "right");
feel free to edit the code snippets as it might be not very tidy after my edits.
In the case of an odd number of items you can get the middle item using Math.floor(items.length / 2). From there you can use prevAll() and nextAll() to add the classes to the relevant elements:
var $items = $('.item');
var middleIndex = Math.floor($items.length / 2);
$items.eq(middleIndex).addClass('center')
.prevAll().addClass('left').end()
.nextAll().addClass('right');
.left { color: red; }
.center { color: green; }
.right { color: blue; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div> <!--the middle one-->
<div class="item">4</div>
<div class="item">5</div>
Without jQuery you might as well do like this;
var els = Array.from(document.querySelectorAll(".item")),
mid = ~~(els.length/2);
els.forEach((e,i) => i < mid ? e.classList.add("left")
: i === mid ? e.classList.add("center")
: e.classList.add("right"));
.left {color: red}
.center {color: green}
.right {color: blue}
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
Without jQuery:
(You haven't responded on how to handle even numbered lists. I've chosen to omit the center class and divide in to two parts: before and after mid)
var setMidClasses = function (elementList, beforeMid, atMid, afterMid) {
var i = 0,
hasMid = elementList.length % 2,
mid = Math.floor(elementList.length / 2);
while (i < mid) {
elementList[i].classList.add(beforeMid);
i += 1;
}
if (hasMid) {
elementList[i].classList.add(atMid);
i += 1;
}
while (i < elementList.length) {
elementList[i].classList.add(afterMid);
i += 1;
}
};
setMidClasses(document.querySelectorAll(".item"),
"top", "mid", "bottom");
.top { background-color: green; }
.mid { background-color: orange; }
.bottom { background-color: yellow; }
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div> <!--the middle one-->
<div class="item">4</div>
<div class="item">5</div>
Here's a version that uses recursion with .first()/.last()
probably not very efficient and could be done with a loop, but I wanted to show a version with recursion.
function fixthem()
{
var divs = $("div:not(.right):not(.left)");
// Handle evens, either 2 in the middle:
if (divs.length <= 2) return;
// or none in the middle
if (divs.length <= 1) return;
divs.first().addClass("left");
divs.last().addClass("right");
fixthem();
}
fixthem();
Here's the same without recursion and only a single jquery find at the start (ie hugely more efficient):
function fixthem()
{
var divs = $("div");
// Use 1 for 1 or none in the middle (when even), 2 for 1(odd) or 2(even)
while (divs.length > 2)
{
divs = divs.filter(":not(.right):not(.left)");
if (divs.length <= 2) break;
divs.first().addClass("left");
divs.last().addClass("right");
}
}
fixthem();
To add the class to the middle, run this after the function/at the end of the while loop:
$("div:not(.right):not(.left)").addClass("center")
Working fiddle: https://jsfiddle.net/5huLjh5q/
With center: https://jsfiddle.net/5huLjh5q/1/
var divs = $("div");
// Use 1 for 1 or none in the middle (when even), 2 for 1(odd) or 2(even)
while (divs.length > 2)
{
divs = divs.filter(":not(.right):not(.left)");
if (divs.length <= 2) break;
divs.first().addClass("left");
divs.last().addClass("right");
}
divs.addClass("center");
div { display:inline; border:1px solid black; padding: 1em; margin-top:0.5em }
.left { border:1px solid red;}
.right { border:1px solid green;}
.center { background: pink; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>

Change child element of array item (syntax)

I have a few divs which are using the same class.
Inside the divs are three more divs with identical classes.
<div class="plane">
<div class="win1">Lorem ipsum</div>
<div class="win2">Dolor sit</div>
<div class="win3">amet.</div>
</div>
<div class="plane">
<div class="win1">Lorem ipsum</div>
<div class="win2">Dolor sit</div>
<div class="win3">amet.</div>
</div>
var allPlanes = $('.plane');
for (var i = 0; i < allPlanes.length; i++) {
var onePlane = allPlanes[i];
var baseHeight = 10;
$(onePlane + " .win1").css("height", parseInt(baseHeight*1));
$(onePlane + " .win2").css("height", parseInt(baseHeight*2));
$(onePlane + " .win3").css("height", parseInt(baseHeight*3));
}
(Don't mind about the names. It's just an example...)
Now I made an array with the outside divs and I can select the single divs inside. But I did not get the right syntax for the child divs inside.
Can anyone help?
My Fiddle: http://jsfiddle.net/SchweizerSchoggi/559xvww6/
Change you script to this:
var allPlanes = $('.plane');
var baseHeight = 10;
$(".plane > .win1").css("height", parseInt(baseHeight*1)+"px");
$(".plane > .win2").css("height", parseInt(baseHeight*2)+"px");
$(".plane > .win3").css("height", parseInt(baseHeight*3)+"px");
You don't need the for loop in such a case.
A prettier way:
var baseHeight = 10;
for (var i = 1; i <= 3; i++) {
$(".plane > .win"+i).css("height", parseInt(baseHeight*i)+"px");
}
http://jsfiddle.net/559xvww6/3/
If you don't want to use a for loop and want to dinamically configure from an array:
var baseHeight = 10;
$.map([1,2,3], function(i) {
$(".plane > .win"+i).css("height", parseInt(baseHeight*i)+"px");
});
http://jsfiddle.net/559xvww6/10/
Edit:: Just a side note: all these approachs are valid, but that doesn't mean that they are the best / most efficient ones. Feel free to use the one you like the most, understand it and try to use it or adapt it to your very personal situation. The "easiest" approach is surely the first one, but it is also the longest one.
isn't this one is better:
var base = 10;
$('.plane > div').css('height', function(){
return base*($(this).index()+1)
});
.plane {
background-color: #ccc;
border: solid 1px #cdcdcd;
margin-bottom: 15px;
}
.plane > .win1 { background-color: #ddd; }
.plane > .win2 { background-color: #eee; }
.plane > .win3 { background-color: #fff; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="plane">
<div class="win1">Lorem ipsum</div>
<div class="win2">Dolor sit</div>
<div class="win3">amet.</div>
</div>
<div class="plane">
<div class="win1">Lorem ipsum</div>
<div class="win2">Dolor sit</div>
<div class="win3">amet.</div>
</div>
You cannot use + operator between a jQuery object and a string.
The correct way to do it is this:
$(".win1", onePlane).css("height", parseInt(baseHeight*1));
$(".win2", onePlane).css("height", parseInt(baseHeight*2));
$(".win3", onePlane).css("height", parseInt(baseHeight*3));
Each of these queries translates to: select all elements with .winX that are inside the jQuery object onePlane.
I would use all the same class names inside the nest and then just do $('.plane:eq(0) .win:eq(2)').html()
alert( $('.plane:eq(0) .win:eq(2)').html() );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="plane">
<div class="win">Lorem ipsum</div>
<div class="win">Dolor sit</div>
<div class="win">amet.</div>
</div>
<div class="plane">
<div class="win">Lorem ipsum</div>
<div class="win">Dolor sit</div>
<div class="win">amet.</div>
</div>
if your classes are fixed then you can do with this code
$(".win1", $(".plane")).css("height", parseInt(baseHeight*1));
$(" .win2", $(".plane")).css("height", parseInt(baseHeight*2));
$(" .win3", $(".plane")).css("height", parseInt(baseHeight*3));
You can do using each loop of plane class.
$('.plane').each(function(){
baseHeight = 10;
$(this).find(".win1").css("height", parseInt(baseHeight*1));
$(this).find(".win2").css("height", parseInt(baseHeight*2));
$(this).find(".win3").css("height", parseInt(baseHeight*3));
});
Demo

Categories

Resources