Using arr.every() on [...HTMLCollection] doesn't return true element change - javascript

I'm trying to build a Tic Tac Toe game so I tried to collect the playbox areas in an array by first using getElementsByClassName() before using spread operator to convert the collection into an array.
But when I try to use the arr.every() method to check if all boxes are played, I still get false even after all the boxes are filled
This is my HTML code
<div class="board">
<div class="board-sections">
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div>
</div>
</div>
First I collected all play boxes.
let boxes = document.getElementsByClassName("play-box");
let numOfBoxes = boxes.length;
Then I converted the collection to array and applied the condition to check if all boxes are not empty
let boxesArr = [...boxes];
let checkBoxes = boxesArr.every(function(box) {
return box.innerHTML !== "";
});
Then I created a function to check if all boxes are not empty
function checkBoard() {
if (checkBoxes) {
console.log("All Filled");
}
}
Then I created a funtion to add text to each box and check if all boxes are filled by calling the checkBoard() function onclick.
for (var i = 0; i < numOfBoxes; i++) {
boxes[i].addEventListener("click", addChip);
}
The addChip() function adds a text to each box as it's clicked, then check if all boxes are filled
function addChip() {
this.innerHTML = "X";
checkBoard();
}
The boxes were filled as they're clicked, and I expected the checkBoard() function to return true after all boxes are filled, but after all boxes have filled the checkBoard() function still returned false.
Here's what the full code looks like
let boxes = document.getElementsByClassName("play-box");
let numOfBoxes = boxes.length;
let boxesArr = [...boxes];
let checkBoxes = boxesArr.every(function(box) {
return box.innerHTML !== "";
});
function checkBoard() {
if (checkBoxes) {
console.log("All Filled");
}
}
for (var i = 0; i < numOfBoxes; i++) {
boxes[i].addEventListener("click", addChip);
}
function addChip() {
this.innerHTML = "X";
checkBoard();
}
.board {
text-align: center;
max-width: 100%;
width: 500px;
margin: auto;
}
.board-sections {
display: grid;
grid-template-columns: auto auto auto;
background: #ccc;
gap: 5px;
align-content: center;
}
.play-box {
height: 100px;
background: transparent;
border: 1px solid #000;
min-width: 100px;
display: flex;
align-items: center;
justify-content: center;
}
<div class="board">
<div class="board-sections">
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div>
</div>
</div>

It is difficult to answer your question without having the actual code. Below I assembled a possible scenario that actually works. Maybe it is helpful to you?
const pb=[...document.querySelectorAll(".play-box")];
document.querySelectorAll("button").forEach(b=>{
b.addEventListener("click",ev=>{
if(b.textContent=="check")
console.log(pb.every(p=>p.textContent!=""))
else
pb.forEach(p=>p.textContent="X");
})
})
.play-box {display:inline-block; width:40px;height:40px; border:1px solid grey}
<div class="board">
<div class="board-sections">
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div><br>
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div><br>
<div class="play-box"></div>
<div class="play-box"></div>
<div class="play-box"></div>
</div>
</div>
<button>check</button> <button>fill</button>
The point I was trying to make is that the .textContent of the .play-box elements must be checked after they have been filled. OP's original script did the check only once, directly after the page was loaded.
Explanation:
The key part in my snippet above is the expression
pb.every(p=>p.textContent!="")
It returns true if all boxes are filled in some way. In your tic-tac-toe game this will need to be executed after each setting of an "X" or an "O".
Your checkBoard function should look like this:
function checkBoard() {
if (boxesArr.every(p=>p.textContent!="")) {
console.log("All Filled");
}
}

Your checkBoxes holds a boolean value, not a function:
// This is wrong
let checkBoxes = boxesArr.every(function(box) {
return box.innerHTML !== "";
});
it will only return the value as the state before the game even started. You cannot reuse it like if (checkBoxes) during the game and expect an updated value.
Instead, return a function that returns a boolean by using it like if (checkBoxes()) {:
const boxes = document.querySelectorAll(".board-box");
const numOfBoxes = boxes.length;
const checkBoxes = () => [...boxes].every((box) => box.textContent.trim() !== "");
function checkBoard() {
if (checkBoxes()) {
console.log("All Filled");
}
}
boxes.forEach((box) => {
box.addEventListener("click", addChip);
});
function addChip() {
this.textContent = "X";
checkBoard();
}
.board {
text-align: center;
max-width: 100%;
width: 500px;
margin: auto;
}
.board-sections {
display: grid;
grid-template-columns: auto auto auto;
background: #ccc;
gap: 5px;
align-content: center;
}
.board-box {
height: 100px;
background: transparent;
border: 1px solid #000;
min-width: 100px;
display: flex;
align-items: center;
justify-content: center;
}
<div class="board">
<div class="board-sections">
<div class="board-box"></div>
<div class="board-box"></div>
<div class="board-box"></div>
<div class="board-box"></div>
<div class="board-box"></div>
<div class="board-box"></div>
<div class="board-box"></div>
<div class="board-box"></div>
<div class="board-box"></div>
</div>
</div>
Also, use textContent to return text instead of innerHTML
Additionally you can simplify the code to:
const boxes = document.querySelectorAll(".board-box");
const tot = boxes.length;
let turn = 0;
const isBoxEmpty = (box) => box.textContent.trim() === "";
const checkBoard = () => {
if (![...boxes].some(isBoxEmpty)) {
console.log("All Filled");
}
};
const addChip = (ev) => {
const box = ev.currentTarget;
if (!isBoxEmpty(box)) return; // Not an empty box. Exit function here.
box.textContent = (turn % 2) ? "O" : "X";
checkBoard();
// Increment turn
turn += 1;
}
boxes.forEach((box) => box.addEventListener("click", addChip));
.board {
font: 14vmin/1 sans-serif;
margin: auto;
display: inline-grid;
grid-template-columns: repeat(3, 1fr);
gap: 5px;
}
.board-box {
height: 20vmin;
aspect-ratio: 1;
border: 2px solid #000;
display: flex;
align-items: center;
justify-content: center;
user-select: none;
}
<div class="board">
<div class="board-box"></div>
<div class="board-box"></div>
<div class="board-box"></div>
<div class="board-box"></div>
<div class="board-box"></div>
<div class="board-box"></div>
<div class="board-box"></div>
<div class="board-box"></div>
<div class="board-box"></div>
</div>

Related

Why drag and drop execute even if drop target element class list attributes doesn't contain draggable element id?

I want a draggable element to be dropped into a drop target element if and only if the drop target element in question contains the draggable element id as one of its class attributes.
So when the draggable element with id="chigaco" is dropped into drop target element whose class list attributes contain "chigaco" the code execute as it should.
When user attempt to drop said element into drop target element whose class list attributes doesn't contain "chigaco" the drop isn't performed. So far so good.
The issue is that instead the code drops the draggable element into the drop target element with class list attribute containing draggable element id. But what I'd like is for my code to do nothing.
Hope I'm making sense. If not try use the "app" and it will be self explanatory
const drags = document.querySelectorAll(".drag");
const empties = document.querySelectorAll(".empty");
for(const drag of drags) {
drag.addEventListener("dragstart", function(e) {
drag.classList.add("purple")
})
drag.addEventListener("dragend", function(e) {
setTimeout(() => drag.classList.remove("purple"), 0)
})
for(const empty of empties) {
empty.addEventListener("dragover", function(e) {
e.preventDefault();
console.log("dragover");
})
empty.addEventListener("dragenter", function(e) {
e.preventDefault()
console.log("dragenter")
})
empty.addEventListener("dragleave", function(e) {
console.log("leave")
console.log(empty)
})
empty.addEventListener("drop", function(e) {
if(empty.classList.contains(drag.id) === false) return
empty.append(drag)
})
}
}
.container {
display: flex;
}
.empty {
border: 1px black solid;
height: 310px;
width: 310px;
margin: 10px;
flex-direction: row;
}
.fill {
border: 1px black solid;
height: 100px;
width: 100px;
margin: 10px;
}
.drag {
border: 1px black solid;
height: 300px;
width: 300px;
margin: 10px;
margin-left: 0;
flex-direction: row;
}
.cointainer1 {
margin-left: 0;
}
.parent {
display: flex;
flex-direction: row;
}
.purple {
background-color: purple;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="index.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css" integrity="sha384-DyZ88mC6Up2uqS4h/KRgHuoeGwBcD4Ng9SiP4dIRy0EXTlnuz47vAwmeGwVChigm" crossorigin="anonymous">
<title></title>
</head>
<body>
<div class="parent">
<div class="container1">
<div id="chigaco" class="drag chigaco" draggable="true">bulls</div>
<div id="losAngeles" class="drag losAngeles" draggable="true">laker</div>
<div id="boston" class="drag boston" draggable="true">celtics</div>
<div id="spurs" class="drag spurs" draggable="true">san Antionio</div>
<div id="knicks" class="drag knicks" draggable="true">New York</div>
</div>
<div class="container2">
<div class="empty chigaco">chigaco</div>
<div class="empty losAngeles">losAngeles</div>
<div class="empty boston">boston</div>
<div class="empty spurs">spurs</div>
<div class="empty knicks">knicks</div>
</div>
</div>
</body>
<script src="index.js" type="text/javascript">
</script>
</html>
The approach was good but there's two main errors here:
Nested listeners. Each drag adds a listener to all empty, these need to be two separate loops, otherwise you are multiplying listeners (drag*empty)
Not storing the dragged element, as it's needed to compare id and class
Here's how to fix it (see comments in JS code)
const drags = document.querySelectorAll(".drag");
const empties = document.querySelectorAll(".empty");
// dragged Element
let currentDrag = null;
// Loop for drags
for(const drag of drags) {
drag.addEventListener("dragstart", function(e) {
drag.classList.add("purple");
currentDrag = e.target; // Store the dragged element
});
drag.addEventListener("dragend", function(e) {
setTimeout(() => {
drag.classList.remove("purple");
currentDrag = null; // Remove the dragged element, not required but consistent in logic
}, 10);
});
}
// Loop for empties
for(const empty of empties) {
empty.addEventListener("dragover", function(e) {
e.preventDefault();
});
empty.addEventListener("drop", function(e, i) {
const dropElement = e.target; // Declaring for clarity
if(!currentDrag || dropElement.classList.contains(currentDrag.id) === false) return
empty.append(currentDrag);
})
}
.container {
display: flex;
}
.empty {
border: 1px black solid;
height: 310px;
width: 310px;
margin: 10px;
flex-direction: row;
}
.fill {
border: 1px black solid;
height: 100px;
width: 100px;
margin: 10px;
}
.drag {
border: 1px black solid;
height: 300px;
width: 300px;
margin: 10px;
margin-left: 0;
flex-direction: row;
}
.cointainer1 {
margin-left: 0;
}
.parent {
display: flex;
flex-direction: row;
}
.purple {
background-color: purple;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css" integrity="sha384-DyZ88mC6Up2uqS4h/KRgHuoeGwBcD4Ng9SiP4dIRy0EXTlnuz47vAwmeGwVChigm" crossorigin="anonymous">
<title></title>
</head>
<body>
<div class="parent">
<div class="container1">
<div id="chigaco" class="drag chigaco" draggable="true">bulls</div>
<div id="losAngeles" class="drag losAngeles" draggable="true">laker</div>
<div id="boston" class="drag boston" draggable="true">celtics</div>
<div id="spurs" class="drag spurs" draggable="true">san Antionio</div>
<div id="knicks" class="drag knicks" draggable="true">New York</div>
</div>
<div class="container2">
<div class="empty chigaco">chigaco</div>
<div class="empty losAngeles">losAngeles</div>
<div class="empty boston">boston</div>
<div class="empty spurs">spurs</div>
<div class="empty knicks">knicks</div>
</div>
</div>
</body>
</html>

I want to create an animation circle that play always and allow click even

Hello guys I want my animation be infinite and when it finish - he restart without any jump space.
and moreover allow to click event to go next position on my animation circle
How can I apply it?
let jump = 0;
let index = 0;
const boxContainer = document.querySelector(".boxContainer");
const animate = () => {
boxContainer.style.transform = `translate(${jump}px)`;
boxContainer.appendChild(boxContainer.children[index].cloneNode(true));
index++;
};
const nextBox = () => {
jump -= 100;
requestAnimationFrame(animate);
};
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
background-color: aqua;
height: fit-content;
width: 500px;
overflow-x: hidden;
position: relative;
}
.anim {
animation: anim 10s infinite linear;
}
.boxContainer {
display: flex;
transition: transform 0.2s;
}
.boxContainer > .box {
width: 90px;
height: 90px;
margin: 5px;
background-color: blue;
flex-shrink: 0;
display: flex;
justify-content: center;
align-items: center;
color: white;
}
.container > button {
position: absolute;
left: 0px;
top: 32px;
width: 50px;
}
#keyframes anim {
to {
transform: translateX(-1000px);
}
}
<div class="container">
<div class="anim">
<div class="boxContainer">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
<div class="box">4</div>
<div class="box">5</div>
<div class="box">6</div>
<div class="box">7</div>
<div class="box">8</div>
<div class="box">9</div>
<div class="box">10</div>
<div class="box">11</div>
<div class="box">12</div>
<div class="box">13</div>
<div class="box">14</div>
<div class="box">15</div>
<div class="box">16</div>
</div>
</div>
<button onclick="nextBox()">next box</button>
</div>
As you can see I create at animation that allow that click event nad he jump to next position but in some place animation restart in wrong place.
How to fix that issue in right and performance way ?

targeting specific class attribute without repeating

I wanted to make a game where you figure out a color combination by clicking on squares. The problem is I cant figure out how to make each individual square change colors instead they all change at once. I looked at several w3schools and mozilla tutorials but they didnt have what i was looking for.
let box = document.querySelectorAll('[data-box]')
for (i = 0; i < box.length; i++) {
box[i].addEventListener('click', () => {
box.forEach(color => {
color.style.backgroundColor = "green"
})
})
}
div.box {
height: 100px;
width: 100px;
margin: 10px;
border: 1px solid black;
}
<div class="box" data-box></div>
<div class="box" data-box></div>
<div class="box" data-box></div>
<div class="box" data-box></div>
They all change at once because you're using box.forEach() to instruct them to all change at once.
You should only change the box that is the target of the current click event:
let box = document.querySelectorAll('[data-box]');
for (i = 0; i < box.length; i++) {
box[i].addEventListener('click', (e) => {
e.target.style.backgroundColor = "green";
})
}
div.box {
height: 100px;
width: 100px;
margin: 10px;
border: 1px solid black;
}
<div class="box" data-box></div>
<div class="box" data-box></div>
<div class="box" data-box></div>
<div class="box" data-box></div>
Alternatively, iterate over the boxes and invoke the event listener on the current iteration target:
let box = document.querySelectorAll('[data-box]');
box.forEach(b => b.addEventListener('click', () => b.style.backgroundColor = 'green'));
div.box {
height: 100px;
width: 100px;
margin: 10px;
border: 1px solid black;
}
<div class="box" data-box></div>
<div class="box" data-box></div>
<div class="box" data-box></div>
<div class="box" data-box></div>

'Backspace' and 'Clear' functions not working in JavaScript calculator

So the title tells most of the story. I am making a pure HTML/CSS/JS calculator and the HTML/CSS went well but I can't seem to get the first couple functions to work. I've already done googling but just comparing code, my code looks like it should work, so I'm stumped. Anyway, here's any potentially relevant code.
var oneBtn = document.getElementById('calc-one');
var twoBtn = document.getElementById('calc-two');
var threeBtn = document.getElementById('calc-three');
var fourBtn = document.getElementById('calc-four');
var fiveBtn = document.getElementById('calc-five');
var sixBtn = document.getElementById('calc-six');
var sevenBtn = document.getElementById('calc-seven');
var eightBtn = document.getElementById('calc-eight');
var nineBtn = document.getElementById('calc-nine');
var zeroBtn = document.getElementById('calc-zero');
var decimalBtn = document.getElementById('calc-decimal');
var clearBtn = document.getElementById('calc-clear');
var backspaceBtn = document.getElementById('calc-backspace');
var displayValElement = document.getElementById('calc-display-val');
var displayVal = '0';
var pendingVal;
var evalStringArray = [];
var calcNumBtns = document.getElementsByClassName('calc-btn-num');
var calcOperatorBtns = document.getElementsByClassName('calc-btn-operator');
var updateDisplayVal = (clickObj) => {
var btnText = clickObj.target.innerText;
if (displayVal === '0')
displayVal = '';
displayVal += btnText;
displayValElement.innerText = displayVal;
}
for (let i = 0; i < calcNumBtns.length; i++) {
calcNumBtns[i].addEventListener('click', updateDisplayVal, false);
}
//for (let i = 0; i < calcOperatorBtns.length; i++) {
// calcOperatorBtns[i].addEventListener('click', performOperation, false)
//}
clearBtn.onClick = () => {
displayVal = '0';
pendingVal = undefined;
evalStringArray = [];
displayValElement.innerHTML = displayVal;
}
backspaceBtn.onClick = () => {
let lengthOfDisplayVal = displayVal.length;
displayVal = displayVal.slice(0, lengthOfDisplayVal - 1);
if (displayVal === '')
displayVal = '0';
displayValElement.innerText = displayVal;
}
#import url('https://fonts.googleapis.com/css?family=Roboto:100&display=swap');
body {
font-family: 'Roboto', sans-serif;
}
.calc-btn {
background-color: silver;
color: black;
width: 25px;
height: 45px;
border: 1px solid gray;
text-align: center;
cursor: pointer;
font-size: 32px;
font-weight: 100;
padding-top: 3px;
}
.calc-btn:hover {
background-color: orange;
}
.row {
display: table;
table-layout: fixed;
width: 200px;
}
.column {
display: table-cell;
}
#calc-zero {
width: 52.66666667px;
border-radius: 0 0 0 7px;
}
#calc-clear {
width: 52.66666667px;
}
#calc-display-val {
height: 80x;
color: white;
text-align: right;
border-left: 1px solid gray;
border-right: 1px solid gray;
border-top: 1px solid gray;
font-size: 48px;
background-color: #383838;
overflow: hidden;
white-space: nowrap;
padding: 12px;
border-radius: 7px 7px 0 0;
}
.calc-btn-operator {
background-color: orange;
color: white;
}
h1 {
text-align: center;
margin-top: 50px;
}
#calc-equals {
border-radius: 0 0 7px 0;
}
#calc-parent {
margin-left: calc(50% - 100px);
}
<head>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<h1>Pure HTML/CSS/JS Calculator</h1>
<div id="calc-parent">
<div class="row">
<div class="column" id="calc-display-val">0</div>
</div>
<div class="row">
<div class="calc-btn column" id="calc-clear">AC</div>
<div class="calc-btn column" id="calc-backspace">⇤</div>
<div class="calc-btn calc-btn-operator column" id="calc-divide">÷</div>
</div>
<div class="row">
<div class="calc-btn calc-btn-num column" id="calc-seven">7</div>
<div class="calc-btn calc-btn-num column" id="calc-eight">8</div>
<div class="calc-btn calc-btn-num column" id="calc-nine">9</div>
<div class="calc-btn calc-btn-operator column" id="calc-multiply">x</div>
</div>
<div class="row">
<div class="calc-btn calc-btn-num column" id="calc-four">4</div>
<div class="calc-btn calc-btn-num column" id="calc-five">5</div>
<div class="calc-btn calc-btn-num column" id="calc-six">6</div>
<div class="calc-btn calc-btn-operator column" id="calc-minus">-</div>
</div>
<div class="row">
<div class="calc-btn calc-btn-num column" id="calc-one">1</div>
<div class="calc-btn calc-btn-num column" id="calc-two">2</div>
<div class="calc-btn calc-btn-num column" id="calc-three">3</div>
<div class="calc-btn calc-btn-operator column" id="calc-plus">+</div>
</div>
<div class="row">
<div class="calc-btn calc-btn-num column" id="calc-zero">0</div>
<div class="calc-btn column" id="calc-decimal">.</div>
<div class="calc-btn calc-btn-operator column" id="calc-equals">=</div>
</div>
</div>
</body>
Using onclick instead of onClick. i.e. lowercase c in onclick will fix your problem.
Changing the backspaceBtn.onClick to backspaceBtn.addEventListener("click", function () { should do the trick. I prepared a fiddle for you here.
At first while using ES6, you should add "Use Strict" at the beginning of your script.
Second ensure the script is run, when the DOM is ready, otherwise getElementById will be undefined, because the element is not rendered yet.
Third you have a typo: try btnBackspace.onclick, which worked on my test. (Using Firefox)
Fourth, might be just here but you forgot the HTML-Tags.

Targeting first element after CSS ordering

Please see this codepen: http://codepen.io/muji/pen/XpEYzO
I need to target the first element after it has been sorted by a css "order" property and give it another CSS property.
Is there some jQuery or something I can use to find the first element after sorting, and then addClass, or something? Many thanks for any help
.wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.featured {
order: 1;
}
.normal {
order: 2;
}
.wrap div {
flex-basis: 50%;
background: #ddd;
border: 2px solid #000;
}
/*this is the part I need help with, as it should only apply to the first element AFTER applying the "order" attribute*/
.wrap div:first-of-type {
flex-basis: 100%;
background: #f00;
}
<h3>wp_query 1 output:</h3>
<div class="wrap">
<div class="normal">Normal</div>
<div class="normal">Normal</div>
<div class="featured">A featured item</div>
<div class="normal">Normal</div>
<div class="featured">A featured item</div>
<div class="normal">Normal</div>
</div>
<h3>wp_query 2 output:</h3>
<div class="wrap">
<div class="normal">Normal</div>
<div class="normal">Normal</div>
<div class="normal">Normal</div>
<div class="normal">Normal</div>
</div>
I'm not aware of any CSS selector for "first in order" or the like (that would be handy, as order becomes more widely-adopted), so it probably will need to be a script-based solution (sadly).
You'd indicated that a solution involving reordering the elements might work for you. If so, that's dead easy. :-) See comments:
// A worker function to tell us the priority of an element (low number = high priority)
function getPriority($el) {
return $el.hasClass("featured") ? 0 : $el.hasClass("normal") ? 1 : 2;
}
// For each .wrap container...
$(".wrap").each(function() {
var $this = $(this);
// Get an array of its child elements
var a = $this.children().get();
// Sort it, putting featured first, then normal, then any others
a.sort(function(a, b) {
return getPriority($(a)) - getPriority($(b));
});
// Append them to the parent, which moves them
$this.append(a);
});
.wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.wrap div {
flex-basis: 50%;
background: #ddd;
border: 2px solid #000;
}
/* Just make the first div the highlighted one */
.wrap div:first-of-type {
flex-basis: 100%;
background: #f00;
}
<h3>wp_query 1 output:</h3>
<div class="wrap">
<div class="normal">Normal</div>
<div class="normal">Normal</div>
<div class="featured">A featured item</div>
<div class="normal">Normal</div>
<div class="featured">A featured item</div>
<div class="normal">Normal</div>
</div>
<h3>wp_query 2 output:</h3>
<div class="wrap">
<div class="normal">Normal</div>
<div class="normal">Normal</div>
<div class="normal">Normal</div>
<div class="normal">Normal</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You could sort inner divs by position().top and apply style on first one.
$('.wrap').each(function() {
var sort = $(this).find('div').sort(function(a, b) {
return $(a).position().top - $(b).position().top
})
$(sort[0]).addClass('first')
})
.wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.featured {
order: 1;
}
.normal {
order: 2;
}
.wrap div {
flex-basis: 50%;
background: #ddd;
border: 2px solid #000;
}
div.first {
flex-basis: 100%;
background: #f00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>wp_query 1 output:</h3>
<div class="wrap">
<div class="normal">Normal</div>
<div class="normal">Normal</div>
<div class="featured">A featured item</div>
<div class="normal">Normal</div>
<div class="featured">A featured item</div>
<div class="normal">Normal</div>
</div>
<h3>wp_query 2 output:</h3>
<div class="wrap">
<div class="normal">Normal</div>
<div class="normal">Normal</div>
<div class="normal">Normal</div>
<div class="normal">Normal</div>
</div>
An alternative to the position top suggested by #Nenad Vracar would be to actually filter the elements with the smallest order in each group and highlight the first one (in terms of dom order)
$('.wrap').each(function() {
var items = $(this).children(),
minOrder = Infinity,
details = items.map(function(i, el) {
var order = +$(el).css('order');
if (minOrder > order) minOrder = order;
return {
element: el,
order: order
};
}).get(),
firstElement = details.filter(function(item) {
return item.order == minOrder;
})[0];
$(firstElement.element)
.addClass('highlight')
.siblings()
.removeClass('highlight');
});
.wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.featured {
order: 1;
}
.normal {
order: 2;
}
.wrap div {
flex-basis: 50%;
background: #ddd;
border: 2px solid #000;
}
/*this is the part I need help with, as it should only apply to the first element AFTER applying the "order" attribute*/
.wrap .highlight {
flex-basis: 100%;
background: #f00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>wp_query 1 output:</h3>
<div class="wrap">
<div class="normal">Normal</div>
<div class="normal">Normal</div>
<div class="featured">A featured item</div>
<div class="normal">Normal</div>
<div class="featured">A featured item</div>
<div class="normal">Normal</div>
</div>
<h3>wp_query 2 output:</h3>
<div class="wrap">
<div class="normal">Normal</div>
<div class="normal">Normal</div>
<div class="normal">Normal</div>
<div class="normal">Normal</div>
</div>
If you were to alter the order based on media queries you should apply this code on resize.

Categories

Resources