I am working with a reactJS app and have the following code:
renderProductBlock(product, index) {
return (
<div className="product col-xs-4">
<span className="product-name">{product.name}</span>
<span className="product-price">{product.price}</span>
Buy Now
</div>
);
}
renderProductList() {
let blocks = [];
_.forEach(product, (item, index) => {
const productBlock = this.renderProductBlock(item, index);
if(productBlock) {
blocks.push(productBlock);
}
});
return blocks;
}
render() {
const productsBlock = this.renderProductList();
if(productsBlock) {
return (
<div className="products">
<div className="row">
{productsBlock}
</div>
</div>
)
}
}
Which is outputting HTML in this layout:
<div class="products">
<div class="row">
<div class="product col-xs-4">
Content
</div>
<div class="product col-xs-4">
Content
</div>
<div class="product col-xs-4">
Content
</div>
<div class="product col-xs-4">
Content
</div>
<div class="product col-xs-4">
Content
</div>
</div>
</div>
What would be the best way for me to add bootstrap rows into these loops to wrap every 3 products in a row div like so:
<div class="products">
<div class="row">
<div class="product col-xs-4">
Content
</div>
<div class="product col-xs-4">
Content
</div>
<div class="product col-xs-4">
Content
</div>
</div>
<div class="row">
<div class="product col-xs-4">
Content
</div>
<div class="product col-xs-4">
Content
</div>
</div>
</div>
Sorry for the slightly simple question but I can't seem to get this right.
Would just keep track of the how many blocks have been processed within the loop and once three blocks are rendered, group them in a row:
renderRow() {
return (
<div class="row">
{block}
</div>
);
}
renderProductList() {
let blocks = [], rows = [];
_.forEach(product, (item, index) => {
const productBlock = this.renderProductBlock(item, index);
if (productBlock) {
blocks.push(productBlock);
}
if (block.length >= 3) {
const row = this.renderRow(blocks);
if (row) {
rows.push(row);
}
blocks = [];
}
});
const row = this.renderRow(blocks);
if (row) {
rows.push(row);
}
return rows;
}
Related
I'm using the index of an item to add an animation delay to elements on my website.
Here's the HTML and JS
<div>
<div class="section section-1">
<div class="item item-1">
</div>
<div class="item item-2">
</div>
</div>
<div class="section section-2">
<div class="item item-1">
</div>
<div class="item item-2">
</div>
<div class="item item-3">
</div>
<div class="item item-4">
</div>
</div>
</div>
const AnimatedElements = document.querySelectorAll(".section .item");
AnimatedElements.forEach((AnimatedElement, index) => {
AnimatedElement.style.setProperty('--index-delay', ([index] * 250) + "ms");
});
Now, this does work. However, The issue I am having is the JS reads the item index as one Array (I.E [0, 1, 2, 3, 4, 5]) rather than two separate arrays within their respective sections (I.E section 1 [0, 1], Section 2 [0, 1, 2, 3]).
Is there any way I can make the index reset to 0 for each new section? As otherwise the animation delay just gets longer and longer the further you scroll down the page.
Edit: I've managed to get the issue fix. However, I have now applied the JS to the columns within the section as well as the items and I am now experiencing the same issue as before.
Here's the updated HTML and JS
<div>
<div class="section section-1">
<div class="column column-1">
<div class="item item-1">
</div>
</div>
<div class="column column-2">
<div class="item item-2">
</div>
</div>
</div>
<div class="section section-2">
<div class="column column-1">
<div class="item item-1">
</div>
<div class="item item-2">
</div>
<div class="item item-3">
</div>
</div>
<div class="column column-2">
<div class="item item-4">
</div>
</div>
</div>
</div>
const Sections = document.querySelectorAll(".section");
const Columns = document.querySelectorAll(".section .column");
Columns.forEach(Column => {
const AnimatedElements = Column.querySelectorAll(".item");
AnimatedElements.forEach((AnimatedElement, index) => {
AnimatedElement.style.setProperty('--index-delay', (index * 250) + "ms");
});
});
Sections.forEach(Section => {
const AnimatedColumns = Section.querySelectorAll(".column");
AnimatedColumns.forEach((AnimatedColumn, index) => {
AnimatedColumn.style.setProperty('--index-delay', (index * 250) + "ms");
});
});
As said before the issue is doing the exact same thing that it did before where the JS reads the column index as one Array (I.E [0, 1, 2, 3]) rather than two separate arrays within their respective sections (I.E section 1 [0, 1], Section 2 [0, 1]).
Any help to fix this issue would be greatly appreciated. Thanks
Use nested loops. The outer loop is for the sections, the inner loop is for the items. The item indexes will start at 0 in each section.
const sections = document.querySelectorAll(".section");
sections.forEach(section => {
const AnimatedElements = section.querySelectorAll(".item");
console.log([...AnimatedElements]);
AnimatedElements.forEach((AnimatedElement, index) => {
AnimatedElement.style.setProperty('--index-delay', (index * 250) + "ms");
});
});
<div>
<div class="section section-1">
<div class="item item-1">1A
</div>
<div class="item item-2">1B
</div>
</div>
<div class="section section-2">
<div class="item item-1">2A
</div>
<div class="item item-2">2B
</div>
<div class="item item-3">2C
</div>
<div class="item item-4">2D
</div>
</div>
</div>
I would like to archive the below by using JavaScript (or with jQuery). Here is the HTML structure:
<div class="score-set">
<div class="score-item">A<div id="score">96+</div></div>
<div class="score-item">B<div id="score">99</div></div>
<div class="score-item">C<div id="score">99</div></div>
<div class="score-item">D<div id="score">96-</div></div>
</div>
<div class="score-set">
<div class="score-item">A<div id="score">86</div></div>
<div class="score-item">B<div id="score">88</div></div>
<div class="score-item">C<div id="score">90</div></div>
<div class="score-item">D<div id="score">90+</div></div>
</div>
<div class="score-set">
<div class="score-item">A<div id="score">83-</div></div>
<div class="score-item">B<div id="score">83+</div></div>
<div class="score-item">C<div id="score">76</div></div>
<div class="score-item">D<div id="score">78</div></div>
</div>
The JavaScript will do the modification, and the desired results will be B 99 C90 A 83- , which looks like:
<div class="score-set">
<div class="score-item">B<div id="score">99</div></div>
</div>
<div class="score-set">
<div class="score-item">C<div id="score">90</div></div>
</div>
<div class="score-set">
<div class="score-item">A<div id="score">83-</div></div>
</div>
The rules are:
Ignore all non-number in id="score", eg. + and -, and do the ranking.
Show one highest score item.
If two score items are the same in a set, show just one according to the div item sequence inside <div class="score-set">, ie. in the above example A > B > C > D.
When writing the result, write the original div item, including + or -.
To be able to do this, it would be best to get each individual score-set and treat one after another.
For each score item, we need to first get the score and transform it (Array#map) into a number with no digits (.replace(\/D+/g, ''))and memorize the score item html object.
Number(scoreItem.querySelector('div').innerText.replace(/\D+/g, ''))
We can then sort the remaining ones in descending order and simply take the first one of the list. Can be done with Array#sort and destructuring assignment.
.sort(({ score: scoreA }, { score: scoreB }) => scoreB - scoreA)
Then finally we update the score set html.
scoreSet.innerHTML = '';
scoreSet.appendChild(scoreItem);
const scoreSets = document.getElementsByClassName('score-set');
for(const scoreSet of scoreSets){
const [{ scoreItem }] = Array
.from(scoreSet.getElementsByClassName('score-item'), scoreItem => ({
scoreItem,
// it would be better here to access the score using the id
// but `score` is used multiple times which makes getting
// the score element unreliable
score: Number(scoreItem.querySelector('div').innerText.replace(/\D+/g, ''))
}))
.sort(({ score: scoreA }, { score: scoreB }) => scoreB - scoreA)
scoreSet.innerHTML = '';
scoreSet.appendChild(scoreItem);
}
<div class="score-set">
<div class="score-item">A
<div id="score">96+</div>
</div>
<div class="score-item">B
<div id="score">99</div>
</div>
<div class="score-item">C
<div id="score">99</div>
</div>
<div class="score-item">D
<div id="score">96-</div>
</div>
</div>
<div class="score-set">
<div class="score-item">A
<div id="score">86</div>
</div>
<div class="score-item">B
<div id="score">88</div>
</div>
<div class="score-item">C
<div id="score">90</div>
</div>
<div class="score-item">D
<div id="score">90+</div>
</div>
</div>
<div class="score-set">
<div class="score-item">A
<div id="score">83-</div>
</div>
<div class="score-item">B
<div id="score">83+</div>
</div>
<div class="score-item">C
<div id="score">76</div>
</div>
<div class="score-item">D
<div id="score">78</div>
</div>
</div>
This can be MUCH simplified
Note I changed the invalid ID to class="score"
If you cannot do that, then change .querySelector(".score") to .querySelector("div")
document.querySelectorAll('.score-set').forEach(scoreSet => {
const scores = [...scoreSet.querySelectorAll(".score-item")];
scores.sort((a,b) => parseInt(b.querySelector(".score").textContent) - parseInt(a.querySelector(".score").textContent))
scoreSet.innerHTML ="";
scoreSet.append(scores[0])
})
<div class="score-set">
<div class="score-item">A
<div class="score">96+</div>
</div>
<div class="score-item">B
<div class="score">99</div>
</div>
<div class="score-item">C
<div class="score">99</div>
</div>
<div class="score-item">D
<div class="score">96-</div>
</div>
</div>
<div class="score-set">
<div class="score-item">A
<div class="score">86</div>
</div>
<div class="score-item">B
<div class="score">88</div>
</div>
<div class="score-item">C
<div class="score">90</div>
</div>
<div class="score-item">D
<div class="score">90+</div>
</div>
</div>
<div class="score-set">
<div class="score-item">A
<div class="score">83-</div>
</div>
<div class="score-item">B
<div class="score">83+</div>
</div>
<div class="score-item">C
<div class="score">76</div>
</div>
<div class="score-item">D
<div class="score">78</div>
</div>
</div>
I need to move some text from demoBoxA to demoBoxB.
The demoBoxA parent element has an id selector, but the child element below it has no identifiable selector.
Is it possible to select the text content directly? Then move it into the demoBoxB sub-element (the demoBoxB sub-element has an id selector)
There are 2 difficulties with this issue.
The content of demoBoxA is dynamically generated by the program and the sort is not fixed. There are no identifiable selectors for the subelements.
only need to select part of the content. For example, in the example below, just move the phone model text of "Google", "Huawei", "BlackBerry".
Any help, thanks in advance!
<div class="container" id="demoBoxA">
<div class="row">
<div class="col-md-6">Samsung</div>
<div class="col-md-6">Galaxy S10</div>
</div>
<div class="row">
<div class="col-md-6">Google</div>
<div class="col-md-6">Pixel 4</div>
</div>
<div class="row">
<div class="col-md-6">Sony</div>
<div class="col-md-6">Xperia 5</div>
</div>
<div class="row">
<div class="col-md-6">Huawei</div>
<div class="col-md-6">Mate 30 5G</div>
</div>
<div class="row">
<div class="col-md-6">BlackBerry</div>
<div class="col-md-6">KEY2</div>
</div>
<div class="row">
<div class="col-md-6">Apple</div>
<div class="col-md-6">iPhone 8</div>
</div>
</div>
<div class="container" id="demoBoxB">
<div class="row">
<div class="col-md-6">Google</div>
<div class="col-md-6" id="pixel"></div>
</div>
<div class="row">
<div class="col-md-6">Huawei</div>
<div class="col-md-6" id="mate"></div>
</div>
<div class="row">
<div class="col-md-6">BlackBerry</div>
<div class="col-md-6" id="key2"></div>
</div>
</div>
You can chain selectors like this:
var rows = document.querySelectorAll("#demoBoxA > .row");
That will return a list of all rows inside of demoBoxA. If you need more info about chaining selectors, you can read about it here.
Then, to move the rows you can do this:
var demoBoxB = document.getElementById('demoBoxB');
rows.forEach((row) => {
demoBoxB.appendChild(row);
});
If you just want the text inside each of the columns, you can do this:
var columns = document.querySelectorAll("#demoBoxA > .col-md-6");
var texts = [];
columns.forEach((column) => {
texts.push(column.innerText);
});
Now, texts is an array of the text contents of each column.
If you want to select the cellphone models for each brand, you can do this:
var cols = Array.from(document.querySelectorAll("#demoBoxA > .col-md-6"));
var samsungCol = cols.find((col) => {
return col.textContent == "Samsung";
});
var samsungPhones = [];
samsungCol.parentNode.childNodes.forEach((col) => {
if (col != samsungCol) {
samsungPhones.push(col);
}
});
Now, samsungPhones is a list of columns, one for each Samsung phone (for example).
You can use html drag api .
Just add draggable=true for elements you want to drag and add event listeners for dragstart and dragend
html
<div class="container" id="demoBoxA">
<div class="row " draggable="true">
<div class="col-md-6">Samsung</div>
<div class="col-md-6">Galaxy S10</div>
</div>
<div class="row" draggable="true">
<div class="col-md-6">Google</div>
<div class="col-md-6">Pixel 4</div>
</div>
<div class="row" draggabble="true">
<div class="col-md-6">Sony</div>
<div class="col-md-6">Xperia 5</div>
</div>
</div>
<div class="container " id="demoBoxB">
<div class="row " draggable="true">
<div class="col-md-6">Google</div>
<div class="col-md-6" id="pixel"></div>
</div>
<div class="row" draggable="true">
<div class="col-md-6">Huawei</div>
<div class="col-md-6" id="mate"></div>
</div>
<div class="row" draggable="true">
<div class="col-md-6">BlackBerry</div>
<div class="col-md-6" id="key2"></div>
</div>
</div>
js
document.addEventListener('dragstart', function(e)
{
item = e.target;
}, false);
document.addEventListener('dragend', function(e)
{
document.getElementById("demoBoxB").appendChild(item)
}, false);
Note : you might have to add conditions to check whether the drop is actually happening in demoboxB
i want to make something like this https://muzzleapp.com/. I want the moving item in right part should be slide up and fade from bottom to top. Items should be moving continuously, so after the last div, it will start from beginning again. I have tried my own code. But stuck on starting from beginning point. It doesn't start properly from beginning.
html
function moveItems(el) {
var x = 1;
var flag = 0;
var elems = $(el).nextAll();
count = elems.length;
elems.each (function (i) {
setTimeout(function() {
if (x>1) {
y = x-1;
$('#slider_'+y).show().delay(2000).slideUp().fadeOut();
}
$('#slider_'+x).show().delay(2000).slideUp();
x++;
if (!--count) {
setTimeout(function() {
moveItems('.panel');
}, 6000)
}
}, i*2000);
})
}
moveItems('.panel');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="panel" id='slider_1'>
<div class="panel-body">
<div class="row">
slider 1
</div>
</div>
</div>
<div class="panel" id='slider_2'>
<div class="panel-body">
<div class="row">
slider 2
</div>
</div>
</div>
<div class="panel" id='slider_3'>
<div class="panel-body">
<div class="row">
slider 3
</div>
</div>
</div>
I updated your logic a little to handle the hide and show. Here is the updated preview https://jsfiddle.net/Aravi/hd465gpc/13/
function moveItems(el) {
var elems = document.querySelectorAll(el);
Array.from(elems).forEach((item,index) => {
setTimeout(function() {
index+=1;
$('#slider_'+index).show().delay(2000).slideUp().fadeOut();
if (index == elems.length) {
setTimeout(function() {
for(j=1;j<= elems.length;j++){ $('#slider_'+j).show()}
moveItems('.panel');
}, 6000)
}
}, index*2000);
})
}
moveItems('.panel');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="panel" id='slider_1'>
<div class="panel-body">
<div class="row">
slider 1
</div>
</div>
</div>
<div class="panel" id='slider_2'>
<div class="panel-body">
<div class="row">
slider 2
</div>
</div>
</div>
<div class="panel" id='slider_3'>
<div class="panel-body">
<div class="row">
slider 3
</div>
</div>
</div>
<div class="panel" id='slider_4'>
<div class="panel-body">
<div class="row">
slider 4
</div>
</div>
</div>
<div class="panel" id='slider_5'>
<div class="panel-body">
<div class="row">
slider 5
</div>
</div>
</div>
I am so confused. I have used this jquery feature for a while now and it will not work here. It returns the right value and prints out to the console but it wont append the data on page load.
HTML :
<div class="row">
<div class="col-xs-12">
<span>Press any key to get started!</span>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<span>Wins</span>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div>Current word: </div>
<br>
<div class="currentWord"></div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<span class="guessRem">Number of guesses remaining:</span>
</div>
</div>
JS :
var hangmanWords = ["baseball", "programming", "movies", "america", "lakers", "gardening"];
var wins = 0;
var remainingGuesses = 12;
function selectAWord (){
var randomVal = hangmanWords[Math.floor(Math.random() * hangmanWords.length)].toString();
$(".currentWord").append(randomVal);
$('.guessRem').append(remainingGuesses);
console.log(randomVal);
return (randomVal);
}
selectAWord();
Try to use the ready function so the DOM will be fully loaded and your elements .currentWord/.guessRem are there for the .append :
$(function(){
//Your function call here
selectAWord();
})
Hope this helps.
$(function(){
selectAWord();
})
function selectAWord (){
var hangmanWords = ["baseball", "programming", "movies", "america", "lakers", "gardening"];
var wins = 0;
var remainingGuesses = 12;
var randomVal = hangmanWords[Math.floor(Math.random() * hangmanWords.length)].toString();
$(".currentWord").append(randomVal);
$('.guessRem').append(remainingGuesses);
console.log(randomVal);
return (randomVal);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row">
<div class="col-xs-12">
<span>Press any key to get started!</span>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<span>Wins</span>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div>Current word: </div>
<br>
<div class="currentWord"></div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<span class="guessRem">Number of guesses remaining:</span>
</div>
</div>