Sorting an array by using a button Sort - javascript

So I am trying to sort an array of numbers when a user clicks on the button sort or reverse and my buttons names are #sort-cards and #reverse-cards. I feel like this is something very simple I am missing but I just cannot figure out what exactly.
(function () {
var cardElements, cardValues; // Do not declare more variables here.
// WRITE CODE HERE TO MAKE THE #cards ELEMENT WORK
//Get an array of all div elements inside the #cards element.
cardElements = Array.from(document.querySelectorAll('#cards div'));
//Initialize the cardValues variable as an empty array.
cardValues = [];
//Use a forEach loop to iterate through each of the div elements (the cards) one by one.
cardElements.forEach(function (cardElements) {
//Generate a card value, a random integer between 1 and 99.
cardElements.textContent = Math.floor(Math.random() * 99) + 1;
//Push it onto the end of the cardValues array and put it in the current div element.
cardValues.push(cardElements);
//Create an event handler that moves the card to the right end whenever it is clicked, leaving the other cards in the same order, and outputs all the new card values to the card divs.
//cardElements.addEventListener('click', function() {
//}
//Do things when the sort button is clicked
document.querySelector('#sort-cards').addEventListener('click', function () {
cardElements.sort(function (a, b){
return a - b;
});
});
//Do things when the reverse button is clicked.
document.querySelector('#reverse-cards').addEventListener('click', function () {
cardElements.reverse();
});
});
}());

You are shadowing cardElements variable in the forEach callback. Also, add the event listeners once, not for every card.
document.querySelectorAll('#cards div') returns a NodeList. If you want to change the DOM, you need to manipulate it, not the JS Array you made out of it.
You can iterate over NodeLists with for ... of.
In order to be DRY, I've added the renderCards function that mutates the DOM.
(function () {
var cardElements, cardValues;
cardElements = document.querySelectorAll('#cards div');
cardValues = [];
function renderCards(newCards) {
for (let i = 0, max = cardElements.length; i < max; i++ ) {
cardElements[i].textContent = newCards[i]
}
}
for (let cardElement of cardElements){
cardElement.textContent = Math.floor(Math.random() * 99) + 1;
cardValues.push(cardElement.textContent);
};
document.querySelector('#sort-cards').addEventListener('click', function () {
cardValues.sort(function (a, b){
return a - b;
});
renderCards(cardValues);
});
document.querySelector('#reverse-cards').addEventListener('click', function () {
cardValues.reverse();
renderCards(cardValues);
});
}());
#cards {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
align-items: center;
width: 100%;
}
.card {
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
margin: 1em;
padding: 1em;
border: 1px solid #ccc;
width: 2em;
height: 2em;
}
#btns {
margin: 1.6em;
}
.btn {
cursor: pointer;
background-color: lightgreen;
padding: 1em;
margin: 0 1.6em;
}
<div id="btns">
<a class="btn" role="btn" id="sort-cards">Sort cards</a>
<a class="btn" role="btn" id="reverse-cards">Reverse cards</a>
</div>
<div id="cards">
<div class="card">1</div>
<div class="card">2</div>
<div class="card">3</div>
<div class="card">4</div>
<div class="card">5</div>
<div class="card">6</div>
<div class="card">7</div>
<div class="card">8</div>
<div class="card">9</div>
<div class="card">10</div>
<div class="card">11</div>
<div class="card">12</div>
</div>

Related

flex-direction row CSS DOM Javascript, set boxes next to eachother in a row. It doesnt work that way

A function that takes 2 arguments: amount and color. The function is gonna create as many boxes as amount and in the color that is given in the argument. The boxes shall lay next to eachother in a row. With margin to seperate the boxes.
I have problem to get them in a row. I have tried flex-direction: row but it doesnt seem to work, they just land in top of eachoter like in a column..
Script:
function antalFärg(a, f){
for(let i=0; i< a; i++){
const div3 = document.createElement('div')
div3.className = 'div3'
div3.style.backgroundColor = `${f}`
console.log(div3)
document.body.appendChild(div3)
}
}
antalFärg(4, 'blue')
Css:
<style>
.div3{
margin: 3px;
display: flex;
flex-direction: row;
height: 100px;
width: 100px;
}
</style>
Your mistake is you have appended it to a body.
Instead, you can create a div and append to it... with basic styles display: flex; flex-direction: row;
function antalFärg(a, f) {
for (let i = 0; i < a; i++) {
const div3 = document.createElement('div')
div3.className = 'div3'
div3.style.backgroundColor = `${f}`
console.log(div3)
document.getElementById("firstDiv").appendChild(div3)
// document.body.appendChild(div3)
}
}
antalFärg(4, 'blue')
.firstDiv {
display: flex;
flex-direction: row;
}
.div3 {
margin: 3px;
height: 100px;
width: 100px;
}
<body>
<div id="firstDiv" class="firstDiv"></div>
</body>

Needing help forcing the div to be stuck right under this other div in CSS

So this is day 2 of making an HTML game. I am honestly convinced I'm making a lot of progress and I am, except, yet again, I run into another styling problem.
So there is a grid in the game that updates every time the game is loaded. Basically, the grid's length and width to the word with the most letters, as shown below:
As you can see, the word everyday is 8 letters long, so the game puts 8 spaces available.
Now here's two problems with this in general:
I want the word bank to be directly UNDER the grid, no matter the length of the grids.
I want the grids to have NO space under them, so you see the little space between every new row? Basically that needs to go poof, and not be there.
What have you tried so far?
Placing the word bank div under the game area div didn't work, so I started to look up some solutions on Google, and it told me to try to add position: absolute; and position: relative; to div 1 and 2, but that just created a mess when it came to the word bank (spacing it out WAY too much) and did nothing to the grids. Also, display: block; can't help, because the code is already using flex for a different reason.
I also tried using margin-bottom for the grid space problem, but did nothing.
Code:
// definitely didn't get the grid part from Stack Overflow
var score = 0;
var scoreDisplay = document.getElementById("score");
scoreDisplay.innerHTML = "<p>Score: " + score;
var wordBank = document.getElementById("wordBank")
var gameArea = document.getElementById("gameArea")
let rows = document.getElementsByClassName("gridRow");
let cells = document.getElementsByClassName("cell");
// sparing you word array, nobody wants to read that list to the very last bits
var selectedWords = []
for (let i = 0; i < 5; i++) {
const selectedWord = words[Math.floor(Math.random() * words.length)]
if (selectedWord.length <= 9) {
wordBank.innerHTML += "<span>" + selectedWord + "</span>"
selectedWords.push(selectedWord)
}
}
var longestWord = selectedWords.reduce((a, b) => a.length < b.length ? b : a, "")
var charCount = longestWord.length
function makeRows(rowNum) {
for (r = 0; r < rowNum; r++) {
let row = document.createElement("div");
gameArea.appendChild(row).className = "gridRow";
};
};
function makeColumns(cellNum) {
for (i = 0; i < rows.length; i++) {
for (j = 0; j < cellNum; j++) {
let newCell = document.createElement("div");
rows[j].appendChild(newCell).className = "cell";
};
};
};
function defaultGrid() {
makeRows(charCount);
makeColumns(charCount);
}
defaultGrid();
body {
margin: 0px;
}
.content {
width: 512px;
height: 512px;
margin-left: auto;
margin-right: auto;
font-family: Arial;
}
.score {
font-size: 24px;
text-align: right;
}
.wordBank {
border: 2.5px solid black;
border-radius: 5px;
font-size: 24px;
display: flex;
width: 100%;
justify-content: space-between;
height: 13%;
}
.wordBank> :nth-of-type(even) {
align-self: flex-end;
}
.gameArea {
width: 100%;
height: 70%;
}
.cell {
border: 1px solid black;
width: 50px;
height: 50px;
display: inline-block;
}
<div class="content" id="content">
<div class="gameArea" id="gameArea">
</div>
<div class="wordBank" id="wordBank">
</div>
<div class="score" id="score">
</div>
</div>
How can I fix this issue? Any help is appreciated!
(Example for David):
One approach is below, with explanatory comments in the code:
// replaced all uses of 'var' with either let (if I anticipated the value would change), or const
// (if the value was likely to be unchanging):
let score = 0;
const scoreDisplay = document.getElementById("score");
const wordBank = document.getElementById("wordBank")
const gameArea = document.getElementById("gameArea")
const rows = document.getElementsByClassName("gridRow");
const cells = document.getElementsByClassName("cell");
// created an Array of words (though ideally a minimal, demonstrative Array would have been in the
// posted MCVE demo code); obviously: replace with your own Array:
const words = ['hello', 'thrifty', 'gaol', 'maester', 'mandible', 'osteoarthritic', 'venerable', 'the', 'cursive'];
let selectedWords = []
// moved this line out of the variable assignments/initialisation, in order that it's easier to
// maintain the code, because related things/actions are in the same/similar place(s):
scoreDisplay.innerHTML = "<p>Score: " + score;
// the rest of the JavaScript I left alone, with the exception of adding a 'let' declaration in the
// for loops after this first one:
for (let i = 0; i < 5; i++) {
const selectedWord = words[Math.floor(Math.random() * words.length)]
if (selectedWord.length <= 9) {
wordBank.innerHTML += "<span>" + selectedWord + "</span>"
selectedWords.push(selectedWord)
}
}
let longestWord = selectedWords.reduce((a, b) => a.length < b.length ? b : a, "")
let charCount = longestWord.length
function makeRows(rowNum) {
for (let r = 0; r < rowNum; r++) {
let row = document.createElement("div");
gameArea.appendChild(row).className = "gridRow";
}
}
function makeColumns(cellNum) {
for (let i = 0; i < rows.length; i++) {
for (let j = 0; j < cellNum; j++) {
let newCell = document.createElement("div");
rows[j].appendChild(newCell).className = "cell";
}
}
}
function defaultGrid() {
makeRows(charCount);
makeColumns(charCount);
}
defaultGrid();
/* added a simple, minimal CSS reset to normalise all element defaults
to a similar layout-sizing method, and font-family: */
*,
::before,
::after {
box-sizing: border-box;
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
/* added this, to help lay out the various elements more clearly: */
.content {
display: grid;
/* defining three rows, each of which is sized to the maximum size
needed to clearly display the content within: */
grid-template-rows: repeat(3, max-content);
/* setting a margin around the element on the block-axis, which is
perpendicular to the inline-axis, the inline-axis being the
direction of writing in the local language; so in left-to-right
languages this results in a top, and bottom, margin of 1em: */
margin-block: 1em;
/* setting a margin of auto on the inline-axis, the left and right
margins of the element in a left-to-right language: */
margin-inline: auto;
/* I retained the width, but removed the height constraint: */
width: 512px;
}
.score {
font-size: 24px;
text-align: right;
}
.wordBank {
border: 2.5px solid #000;
border-radius: 5px;
display: flex;
/* I left this part more ore less alone, other than adjusting
the font-size to an 'em' based sizing for responsive purposes: */
font-size: 1.6em;
/* added a minimum height, in order to allow room for the words
to move to the end within the space: */
min-height: 3em;
justify-content: space-between;
padding: 0.25em;
}
.wordBank span:nth-child(even) {
align-self: end;
}
.gameArea {
/* removing the spaces below/between each .gridRow element, which are caused by
the newline and whitespace characters between the .gridRow elements: */
font-size: 0;
/* placing the game area 'board' horizontally centered in the layout */
justify-self: center;
max-width: 100%;
}
.cell {
border: 1px solid black;
width: 50px;
/* resetting the font-size, so that text is visible once more (despite the parent
having a font-size of 0): */
font-size: 1rem;
height: 50px;
display: inline-block;
}
<div class="content" id="content">
<div class="gameArea" id="gameArea">
</div>
<div class="wordBank" id="wordBank">
</div>
<div class="score" id="score">
</div>
</div>
JS Fiddle demo.
Further to the question in the comments (below):
[...]one problem, why do only four words appear [in] certain instances?
This is a result of your loop, and its check:
// here, i is initialised to 0 (first iteration),
// the assessment is then executed; if it evaluates
// to true the loop runs an iteration, otherwise
// if the assessment returns false the loop stops;
// after the assessment i is incremented:
for (let i = 0; i < 5; i++) {
// selecting a random word:
const selectedWord = words[Math.floor(Math.random() * words.length)]
// testing the length of that random word:
if (selectedWord.length <= 9) {
// if the 'if' statement evaluates to true:
wordBank.innerHTML += "<span>" + selectedWord + "</span>"
// adding the selectedWord to the selectedWords Array
selectedWords.push(selectedWord)
// if the 'if' statement evaluates to false nothing
// happens, the loop runs another iteration; this
// 'consumes' a loop but no word was added hence
// a smaller selectedWords Array
}
}
To guard against this, you could modify your loop:
let score = 0;
const scoreDisplay = document.getElementById("score");
const wordBank = document.getElementById("wordBank")
const gameArea = document.getElementById("gameArea")
const rows = document.getElementsByClassName("gridRow");
const cells = document.getElementsByClassName("cell");
const words = ['hello', 'thrifty', 'gaol', 'maester', 'mandible', 'osteoarthritic', 'venerable', 'the', 'cursive'];
let selectedWords = [];
scoreDisplay.innerHTML = "<p>Score: " + score;
// using a while() loop, and testing the length of the selectedWords Array, so that
// while the condition is true (and the Array-length is less than 5) the loop will
// continue running:
while (selectedWords.length < 5) {
// select random word:
const selectedWord = words[Math.floor(Math.random() * words.length)];
// test the length of that word is less than 9 characters:
if (selectedWord.length <= 9) {
// adding content to the wordBank element:
wordBank.innerHTML += "<span>" + selectedWord + "</span>"
// pushing the word to the Array:
selectedWords.push(selectedWord);
// if no word is added to the Array, the length of the Array doesn't change
// and so the while loop will run again.
}
}
let longestWord = selectedWords.reduce((a, b) => a.length < b.length ? b : a, "")
let charCount = longestWord.length
function makeRows(rowNum) {
for (let r = 0; r < rowNum; r++) {
let row = document.createElement("div");
gameArea.appendChild(row).className = "gridRow";
}
}
function makeColumns(cellNum) {
for (let i = 0; i < rows.length; i++) {
for (let j = 0; j < cellNum; j++) {
let newCell = document.createElement("div");
rows[j].appendChild(newCell).className = "cell";
}
}
}
function defaultGrid() {
makeRows(charCount);
makeColumns(charCount);
}
defaultGrid();
*,
::before,
::after {
box-sizing: border-box;
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
.content {
display: grid;
grid-template-rows: repeat(3, max-content);
margin-block: 1em;
margin-inline: auto;
width: 512px;
}
.score {
font-size: 24px;
text-align: right;
}
.wordBank {
border: 2.5px solid #000;
border-radius: 5px;
display: flex;
font-size: 1.6em;
min-height: 3em;
justify-content: space-between;
padding: 0.25em;
}
.wordBank span:nth-child(even) {
align-self: end;
}
.gameArea {
font-size: 0;
justify-self: center;
max-width: 100%;
}
.cell {
border: 1px solid black;
width: 50px;
font-size: 1rem;
height: 50px;
display: inline-block;
}
<div class="content" id="content">
<div class="gameArea" id="gameArea">
</div>
<div class="wordBank" id="wordBank">
</div>
<div class="score" id="score">
</div>
</div>
JS Fiddle demo.
Note that there is an infinitesimally small chance that this may lead to an infinite loop – though to do so would require that every iteration of the while loop selects a random word longer than 9 characters in length – so it may be worth modifying further, to filter the Array and first remove all words with more than 9 characters:
// you didn't include your own Array, so I'm not sure how
// it's assigned; but you should be able to use
// Array.prototype.filter():
const words = ['hello', 'thrifty', 'gaol', 'maester', 'mandible', 'osteoarthritic', 'venerable', 'the', 'cursive']
// here we use an Arrow function to filter the words
// of the words Array:
.filter(
// passing in a reference to the current Array-element
// ('word') of the Array over which we're iterating;
// here we're testing that the length of the current
// word is less than 9; if so this assessment returns
// Boolean true, and the word is retained in the Array,
// otherwise it returns false and the word is discarded:
(word) => word.length < 9
);
// ...code omitted for brevity...
// again, using a while loop, to ensure that we
// have five Array-elements in the selectedWords
// Array:
while (selectedWords.length < 5) {
// no 'if' to check the length, as it's now
// unnecessary to do so:
const selectedWord = words[Math.floor(Math.random() * words.length)];
wordBank.innerHTML += "<span>" + selectedWord + "</span>"
selectedWords.push(selectedWord);
}
let score = 0;
const scoreDisplay = document.getElementById("score");
const wordBank = document.getElementById("wordBank")
const gameArea = document.getElementById("gameArea")
const rows = document.getElementsByClassName("gridRow");
const cells = document.getElementsByClassName("cell");
const words = ['hello', 'thrifty', 'gaol', 'maester', 'mandible', 'osteoarthritic', 'venerable', 'the', 'cursive'];
let selectedWords = [];
scoreDisplay.innerHTML = "<p>Score: " + score;
// using a while() loop, and testing the length of the selectedWords Array, so that
// while the condition is true (and the Array-length is less than 5) the loop will
// continue running:
while (selectedWords.length < 5) {
// select random word:
const selectedWord = words[Math.floor(Math.random() * words.length)];
// test the length of that word is less than 9 characters:
if (selectedWord.length <= 9) {
// adding content to the wordBank element:
wordBank.innerHTML += "<span>" + selectedWord + "</span>"
// pushing the word to the Array:
selectedWords.push(selectedWord);
// if no word is added to the Array, the length of the Array doesn't change
// and so the while loop will run again.
}
}
let longestWord = selectedWords.reduce((a, b) => a.length < b.length ? b : a, "")
let charCount = longestWord.length
function makeRows(rowNum) {
for (let r = 0; r < rowNum; r++) {
let row = document.createElement("div");
gameArea.appendChild(row).className = "gridRow";
}
}
function makeColumns(cellNum) {
for (let i = 0; i < rows.length; i++) {
for (let j = 0; j < cellNum; j++) {
let newCell = document.createElement("div");
rows[j].appendChild(newCell).className = "cell";
}
}
}
function defaultGrid() {
makeRows(charCount);
makeColumns(charCount);
}
defaultGrid();
*,
::before,
::after {
box-sizing: border-box;
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
.content {
display: grid;
grid-template-rows: repeat(3, max-content);
margin-block: 1em;
margin-inline: auto;
width: 512px;
}
.score {
font-size: 24px;
text-align: right;
}
.wordBank {
border: 2.5px solid #000;
border-radius: 5px;
display: flex;
font-size: 1.6em;
min-height: 3em;
justify-content: space-between;
padding: 0.25em;
}
.wordBank span:nth-child(even) {
align-self: end;
}
.gameArea {
font-size: 0;
justify-self: center;
max-width: 100%;
}
.cell {
border: 1px solid black;
width: 50px;
font-size: 1rem;
height: 50px;
display: inline-block;
}
<div class="content" id="content">
<div class="gameArea" id="gameArea">
</div>
<div class="wordBank" id="wordBank">
</div>
<div class="score" id="score">
</div>
</div>
JS Fiddle demo.
You probably want to do something like this:
So, what I did was to place the .game-grid(the n by n grid) and .words-wrapper (the zig zag word cloud) in a .container. This .container is a flex that flows in a column. This shows the 2 items inside the .container one by one from top to bottom.
.game-grid itself is a grid. This lets you easily create a grid.
grid-template-colums: repeat(8, 1fr) tells the browser that this grid is going to have 8 columns (this you will have to control by the length of the longest word). I set the grid to have a fixed size and all the items inside have place-items: stretch which means they take all the available space, so they will all be equal size.
Hope this helps.
.container {
display: flex;
flex-direction: column;
width: 100%;
height: 100vh;
align-items: center;
}
.game-grid {
width: 50vh;
height: 50vh;
display: grid;
grid-template-columns: repeat(8, 1fr);
place-items: stretch;
place-content: stretch;
}
.game-grid-item {
border-width: 1px;
border-style: solid;
border-color: chocolate;
width: 100%;
height: 100%;
display: grid;
place-items: center;
}
.words-wrapper {
display: flex;
width: 100%;
justify-content: space-between;
height: 10vh;
border-width: 1px;
border-style: solid;
border-color: blueviolet;
}
.even {
align-self: flex-end;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div class="container">
<div class="game-grid">
<div class="game-grid-item">1</div>
<div class="game-grid-item">2</div>
<div class="game-grid-item">3</div>
<div class="game-grid-item">4</div>
<div class="game-grid-item">5</div>
<div class="game-grid-item">6</div>
<div class="game-grid-item">7</div>
<div class="game-grid-item">8</div>
<div class="game-grid-item">9</div>
<div class="game-grid-item">10</div>
<div class="game-grid-item">11</div>
<div class="game-grid-item">12</div>
<div class="game-grid-item">13</div>
<div class="game-grid-item">14</div>
<div class="game-grid-item">15</div>
<div class="game-grid-item">16</div>
<div class="game-grid-item">1</div>
<div class="game-grid-item">2</div>
<div class="game-grid-item">3</div>
<div class="game-grid-item">4</div>
<div class="game-grid-item">5</div>
<div class="game-grid-item">6</div>
<div class="game-grid-item">7</div>
<div class="game-grid-item">8</div>
<div class="game-grid-item">9</div>
<div class="game-grid-item">10</div>
<div class="game-grid-item">11</div>
<div class="game-grid-item">12</div>
<div class="game-grid-item">13</div>
<div class="game-grid-item">14</div>
<div class="game-grid-item">15</div>
<div class="game-grid-item">16</div>
<div class="game-grid-item">1</div>
<div class="game-grid-item">2</div>
<div class="game-grid-item">3</div>
<div class="game-grid-item">4</div>
<div class="game-grid-item">5</div>
<div class="game-grid-item">6</div>
<div class="game-grid-item">7</div>
<div class="game-grid-item">8</div>
<div class="game-grid-item">9</div>
<div class="game-grid-item">10</div>
<div class="game-grid-item">11</div>
<div class="game-grid-item">12</div>
<div class="game-grid-item">13</div>
<div class="game-grid-item">14</div>
<div class="game-grid-item">15</div>
<div class="game-grid-item">16</div>
<div class="game-grid-item">1</div>
<div class="game-grid-item">2</div>
<div class="game-grid-item">3</div>
<div class="game-grid-item">4</div>
<div class="game-grid-item">5</div>
<div class="game-grid-item">6</div>
<div class="game-grid-item">7</div>
<div class="game-grid-item">8</div>
<div class="game-grid-item">9</div>
<div class="game-grid-item">10</div>
<div class="game-grid-item">11</div>
<div class="game-grid-item">12</div>
<div class="game-grid-item">13</div>
<div class="game-grid-item">14</div>
<div class="game-grid-item">15</div>
<div class="game-grid-item">16</div>
</div>
<div class="words-wrapper">
<span class="item">multiply</span>
<span class="item even">step</span>
<span class="item">kiss</span>
<span class="item even">force</span>
<span class="item">ago</span>
</div>
</div>
</body>
</html>

how to iterate over an h1 element and make each word fade in with jquery?

I would like to know how to iterate over the h1 element, and get each word to fade in one after the other.
I got it done, but the code is not dry. Can someone please show and explain how to do this with a loop?
$('document').ready(function() {
$('#H').fadeIn(3000).removeClass("hidden").addClass("hColor1");
$('#e').fadeIn(5000).removeClass("hidden").addClass("hColor2");
$('#l').fadeIn(6000).removeClass("hidden").addClass("hColor3");
$('#secondL').fadeIn(7000).removeClass("hidden").addClass("hColor4");
$('#o').fadeIn(7300).removeClass("hidden").addClass("hColor5");
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="container">
<h1 class="hidden"><span id="H">Hello</span> <span id="e">everyone</span> <span id="l">lets</span> <span id="secondL">learn</span> <span id="o">javascript</span></h1>
</div>
I wouldn't hide the < h1 > but the spans inside, then use setTimeout() to delay each fadeIn()
$('document').ready(function(){
var spans = $("h1").find("span"); // Get all spans inside <h1>
spans.hide(); // hide spans
var show_time = 1000; // set time for first span
$.each(spans, function(i, item){ // item = every span
setTimeout(function(){ // setTimeout delays events
$(item).fadeIn('slow') // fadeIn to show each item (span)
}, show_time); // showtime after function inside setTimeout
show_time = show_time + 1000; // increase 1 sec for every span
});
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<h1 class="">
<span id="H">Hello</span>
<span id="e">everyone</span>
<span id="l">lets</span>
<span id="secondL">learn</span>
<span id="o">javascript</span>
</h1>
</div>
The code below does the following:
Gets the words from the h1 element and splits them by whitespace into an array.
Using the array of words, it creates an html string with span elements surrounding each word.
Inserts the html back into the h1 element.
Hides all the span elements.
Shows the h1 element (but nothing will show at this point because all the span children are hidden).
Fades in the span elements one after another.
The last step is accomplished by passing a function as the second parameter to the .fadeIn() function. That function is called after the element is finished fading in.
The fading is done in a function named fadeInNext(). That function is called initially for the first child element, but it calls itself for the next element when the fading is finished. That will continue until all child elements have been faded in.
$(function() {
var $header = $('#hdr');
$header.html($.map($header.text().split(/\s+/), function(word) {
return '<span>' + word + '</span>';
}).join(' ')).children().hide().end().show();
(function fadeInNext($element) {
$element.fadeIn('slow', function() {
fadeInNext($element.next());
});
})($header.children(':first'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 id="hdr" style="display: none;">Hello everyone lets learn javascript</h1>
jsfiddle showing the code in re-usable functions.
jsfiddle fading in letters, instead of words.
// get your text string
var hello = $('.hello').text();
// empty text container so we can refill it later
$('.hello').empty();
// split string by each word and save to array
var helloArray = hello.split(' ');
// adjust these values to customize how slow/fast your words appear
var delays = [400, 500, 1500, 1600, 1900];
// for each word in the array..
$(helloArray).each(function(i) {
// cant use this inside the setTimeout function so we save this as a variable
var pseudoThis = this;
// begin the setTimeout function to stagger/delay the word appearance
setTimeout(function() {
// the html to wrap each word with for customizing css
wordAndWrapper = '<span class="hColor n'+i+'">'+pseudoThis+'</span> ';
// append html with variables inserted to text container
$('.hello').append(wordAndWrapper);
// i is used here to get the position in the delays array
}, delays[i]);
// if its the last word (or any word you want to emphasize as we've done with 'javascript' here)
if (i === 4) {
setTimeout(function() {
// custom css styling for last word using a class
$('.n4').addClass('grow');
// had to make the delay 50ms more than delay of appearance so that transition in css applies
}, 1950);
};
})
html, body {
margin: 0;
background-color: hsla(0, 0%, 90%, 1);
}
.wrapper {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
}
.hello {
display: flex;
justify-content: space-evenly;
align-items: center;
flex-wrap: wrap;
margin: 0;
text-align: center;
font-size: 4vw;
font-weight: bold;
}
.hColor {
display: flex;
justify-content: center;
width: 25%;
padding: 0 30px;
box-sizing: border-box;
transition: all 0.2s linear;
}
.hColor.n0 { color: hsl(0, 51.2%, 49.8%); }
.hColor.n1 { color: hsl(190.7, 93.7%, 43.5%); }
.hColor.n2 { color: hsl(36, 70.9%, 51.6%); }
.hColor.n3 { color: hsl(286, 71.8%, 44.5%); }
.hColor.n4 { width: 100%; font-variant: small-caps; color: hsl(107.9, 83.6%, 45.5%); }
.hColor.n4.grow { font-size: 11vw; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<h1 class="hello">Hello Everyone Let's Learn javascript</h1>
</div>
fiddle
https://jsfiddle.net/Hastig/vorj57gs/
credit
Get text, put each word into an array .split
Using setTimeout in the .each loop
you can do by .each()
$('document').ready(function() {
$('.hidden *').each(function(index) {
$(this).fadeIn((index + 1) * 1000).addClass('hColor' + (index + 1));
});
})
.hColor1 {
background: pink;
}
.hColor2 {
background: lightblue;
}
.hColor3 {
background: lightgreen;
}
.hColor4 {
background: lightgrey;
}
.hColor5 {
background: lightyellow;
}
h1.hidden * {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<h1 class="hidden">
<span id="H">
Hello
</span>
<span id="e">
everyone
</span>
<span id="l">
lets
</span>
<span id="secondL">
learn
</span>
<span id="o">
javascript
</span>
</h1>
</div>

How to cycle through DIVs

I want my page to show 3 divs at a time, and when I click next I would like it to show the next 3 divs. Then when I click previous, I would like to display the previous 3.
$("#container .result").slice(0, 3).show();
$("#right").click(function () {
var items = $('#container .result:visible').hide().last();
var nextItems = items.nextAll().slice(0, 3);
if (nextItems.length === 0) {
nextItems = $("#container .result").slice(0, 3);
}
nextItems.show();
});
$("#left").click(function () {
var items = $('#container .result:visible').hide().last();
var nextItems = items.prevAll().slice(0, 3);
if (nextItems.length === 0) {
nextItems = $("#container .result").slice(0, 3);
}
nextItems.show();
});
The problem is that when I click previous, and it comes to last 3 divs and when I click again it shows 2 than 1. How can i fix that? I want it to stop when it comes to first 3.
You were very much on the right track, I was impressed by the ingenuity of your code.
Your main problem is solved with a very simple fix; in the #left click-handler, replace .last() with .first():
var items = $('#container .result:visible').hide().first();
And to loop around to the last 3 when you click previous on the first 3, change this line to the next:
nextItems = $("#container .result").slice(0, 3);
nextItems = $("#container .result").slice($("#container .result").length-3, $("#container .result").length);
But I thought the situation might occur, now or in the future, that the number of .results aren't a multitude of 3, let's say 7 or 11 for example.
I created a script that will handle that, and also loop around in both directions:
$("#container .result").first().show(); //initialize divs at pageload
$(".nav").click(function() {
var start=0, step=3;
var currentItems = $("#container .result:visible").hide();
var currentLast = (this.id==="prev" ? currentItems.first() : currentItems.last());
var nextItems = (this.id==="prev" ? currentLast.prevAll() : currentLast.nextAll());
if (nextItems.length === 0) { //if the last set of divs has been reached, loop around
var itemsLength = $("#container .result").length;
if (this.id==="prev") {start=itemsLength-step; step=itemsLength;} //determine wich way to loop around
nextItems = $("#container .result").slice(start,step); //loop around
} else if (nextItems.length < step) { //if the next divs aren't a full set, keep some divs from the current set visible
if (this.id==="prev") {step-=nextItems.length;} else {start=nextItems.length;} //determine which current items should remain visible
currentItems.slice(start,step).each(function(){nextItems.push(this);}); //add selected current items to nextItems-array
} else {nextItems=nextItems.slice(start,step);} //if the next divs are a full set, simply select the next set
nextItems.show(); //show the next set
}).click(); //initialize divs at pageload
In HTML, I gave the two buttons both a class "nav" (see code snippet below), so that I could combine their click-handlers into one.
I changed your first line to this: $("#container .result").first().show();. That line - in combination with the .click() chained to the click-handler - replaces your line: $("#container .result").slice(0, 3).show(); (at the top of your script).
This gives you much more flexibility to change the amount of divs you want to show on the page at once. At the start of the click-handler I declare var step=3;, which is the only place that number is hard-coded, so if you ever want to change the amount you only have to change that number (and maybe adjust some styling).
The rest of the explanation is in the comments in the code.
See the code snippet below for a demo:
$("#container .result").first().show(); //initialize divs at pageload
$(".nav").click(function() {
var start=0, step=3;
var currentItems = $("#container .result:visible").hide();
var currentLast = (this.id==="prev" ? currentItems.first() : currentItems.last());
var nextItems = (this.id==="prev" ? currentLast.prevAll() : currentLast.nextAll());
if (nextItems.length === 0) { //if the last set of divs has been reached, loop around
var itemsLength = $("#container .result").length;
if (this.id==="prev") {start=itemsLength-step; step=itemsLength;} //determine wich way to loop around
nextItems = $("#container .result").slice(start,step); //loop around
} else if (nextItems.length < step) { //if the next divs aren't a full set, keep some divs from the current set visible
if (this.id==="prev") {step-=nextItems.length;} else {start=nextItems.length;} //determine which current items should remain visible
currentItems.slice(start,step).each(function(){nextItems.push(this);}); //add selected current items to nextItems-array
} else {nextItems=nextItems.slice(start,step);} //if the next divs are a full set, simply select the next set
nextItems.show(); //show the next set
}).click(); //initialize divs at pageload
html,body {width:98%; height:90%;}
#container {width:100%; height:90%; background:lightgrey;}
#container .result {display:none; float:left; width:30%; height:100%; margin:0 1.66%; background:lightgreen;}
#container .result > div {display:table; width:100%; height:100%;}
#container .result > div > div {display:table-cell; width:100%; height:100%; text-align:center; vertical-align:middle; font:bolder 2em sans-serif;}
.nav {margin-top:2%; cursor:pointer;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div class="result"><div><div>1</div></div></div>
<div class="result"><div><div>2</div></div></div>
<div class="result"><div><div>3</div></div></div>
<div class="result"><div><div>4</div></div></div>
<div class="result"><div><div>5</div></div></div>
<div class="result"><div><div>6</div></div></div>
<div class="result"><div><div>7</div></div></div>
</div>
<button type="button" class="nav" id="prev">PREVIOUS</button>
<button type="button" class="nav" id="next">NEXT</button>
codepen: https://codepen.io/anon/pen/YQoJzd?editors=1010
jsfiddle: https://jsfiddle.net/k8ysj6gq/1/
You can ignore the CSS and HTML (except for the class="nav" on the buttons), that's all just so we can see it. All the relevant code is in the JS.
Basically you can do something like below.
On Next or Previous click set margin-left of container to position or loop through all div.
$(document).ready(function() {
$('.next-button').on('click', function() {
if (parseInt($('.carousel-item').css("margin-left").slice(0, -2)) < -2000) {
$('.carousel-item').animate({
"margin-left": "0px"
}, 200)
} else {
$('.carousel-item').animate({
"margin-left": "-=600px"
}, 200);
}
});
$('.prev-button').on('click', function() {
if (parseInt($('.carousel-item').css("margin-left").slice(0, -2)) > 0) {
$('.carousel-item').animate({
"margin-left": "-2000px"
}, 200)
} else {
$('.carousel-item').animate({
"margin-left": "+=600px"
}, 200);
}
});
});
.carousel-container {
height: 500px;
display: flex;
margin: 40px 20px;
position: relative;
overflow: hidden;
width: 720px;
padding: 0;
border: 1px solid red;
align-items: center;
}
.carousel-item {
height: 100%;
margin: 5px;
margin-left: 60px;
padding: 0;
-moz-box-orient: horizontal;
-ms-box-orient: horizontal;
-webkit-box-orient: horizontal;
-o-box-orient: horizontal;
box-orient: horizontal;
display: -moz-box;
display: -ms-box;
display: -webkit-box;
display: -o-box;
display: box;
list-style-type: none;
}
.item {
border: solid 1px #333;
margin-right: 10px;
width: 200px;
display: flex;
align-items: center;
}
.item>a {
width: 100%;
display: flex;
justify-content: center;
align-items: flex-end;
}
.prev-button,
.next-button {
border: 1px solid green;
background-color: gray;
}
.navigation {
width: 60px;
margin: 0;
position: absolute;
top: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
}
.next-button:hover,
.prev-button:hover {
background-color: red;
}
.navigation:active {
color: white;
}
.next-button {
right: 0;
}
.prev-button {
left: 0;
}
/* .carousel-item li:nth-child(1) {
background-image: url('http://urbanphenomena.net/imgs/cover/bq2.jpg');
background-size: cover;
} */
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="carousel-container">
<a class="prev-button navigation" href="#">
<</a>
<div class="carousel-item">
<li class="item"> 1 </li>
<li class="item"> 2 </li>
<li class="item"> 3 </li>
<li class="item"> 4 </li>
<li class="item"> 5 </li>
<li class="item"> 6 </li>
<li class="item"> 7 </li>
<li class="item"> 8 </li>
<li class="item"> 9 </li>
<li class="item">
</li>
</div>
<a class="next-button navigation" href="#">></a>
</div>
Run co
Ok so your first mistake was that when trying to code back 3 you were getting the previous 3 items from the first of the 3 not the last. So i changed .last() to .first(). Then to loop back when previous = 0 all you did was slice from the current 3, instead of slicing at the end of the entire array of elements.
Here's a link to a codepen that has the working code(you'll obviously have to change the variables to fit your project): https://codepen.io/anon/pen/qjzxee?editors=1010
changed var items = $('#container .result:visible').hide().last(); to var items = $('#container .result:visible').hide().first();
and
if (nextItems.length === 0) {
nextItems = $("#container .result").slice(0, 3);
}
to
if (nextItems.length === 0) {
var allItems = $("#container .result");
nextItems = $("li").slice(allItems.length - 3,allItems.length);
}
this also only works if the number elements is a multiple of the number you are skipping each time, but i can fix that if you'd like

Show only a few users and hide others

Can anyone explain how to make a user list like as shown in the image below...
I'm making a project in Meteor and using Materialize for template and I want to display the list of assigned users. If there are more than a particular count(say 5) of users i want them to be displayed like on that image... I have tried googling this and haven't found anything useful. I also checked the Materialize website and found nothing useful. So if anyone has an idea please help share it.
Ok so this is the output html, in this case i only have one member but in real case I will have more:
<div class="row"> ==$0
<label class="active members_padding_card_view">Members</label>
<div class="toolBarUsers flex" style="float:right;">
<dic class="other-profile" style="background-color:#f06292;">
<span>B</span>
</div>
This is the .js code
Template.profile.helpers({
randomInitials: function () {
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var nLetter = chars.charAt(Math.floor(Math.random()*chars.length));
var sLetter = chars.charAt(Math.floor(Math.random()*chars.length));
return nLetter + sLetter;
},
tagColor: function () {
var colors = ["#e57373","#f06292","#ba68c8","#9575cd","#7986cb","#64b5f6","#4fc3f7","#4dd0e1","#4db6ac","#81c784","#aed581","#dce775","#fff176","#ffd54f","#ffb74d","#ff8a65","#a1887f","#e0e0e0","#90a4ae"];
return colors[Math.floor(Math.random()*colors.length)];
},
randomAllowed : function(possible) {
var count = Math.floor((Math.random() * possible) + 1);
if(count == 1) {
return;
}
return "none";
},
membersList() {
const instance = Template.instance();
const cardDataId = new Mongo.ObjectID(instance.data.cardData._id.valueOf());
return CardDataMembers.find({lkp_card_data_fkeyi_ref: cardDataId});
},
memberData: function() {
// We use this helper inside the {{#each posts}} loop, so the context
// will be a post object. Thus, we can use this.xxxx from above memberList
return Meteor.users.findOne(this.lkp_user_fkeyi_ref);
},
showMembers() {
const instance = Template.instance();
const cardDataId = new Mongo.ObjectID(instance.data.cardData._id.valueOf());
let membersCount = CardDataMembers.find({lkp_card_data_fkeyi_ref: cardDataId}).count();
////console.log(membersCount);
if (membersCount > 0) {
$('.modal-trigger').leanModal();
return true;
} else {
return false;
}
},
});
Right now if I add a lot of users I get this:
This can be done in many ways, but I've used CSS Flexbox.
I've used two <div>s one contains single user circles having class .each-user that is expanding (for reference I've taken 6) and another contains the total number of users having class .total-users.
It's a bit confusing but if you look into my code below or see this Codepen you'll get to know everything.
html, body {
width: 100%;
height: 100%;
margin: 0;
font-family: Roboto;
}
.container {
display: flex;
align-content: center;
justify-content: center;
margin-top: 20px;
}
/* Contains all the circles */
.users-holder {
display: flex;
}
/* Contains all circles (those without total value written on it) */
.each-user {
display: flex;
flex-wrap: wrap;
padding: 0 10px;
max-width: 300px;
height: 50px;
overflow: hidden;
}
/* Circle Styling */
.circle {
width: 50px;
height: 50px;
border-radius: 50%;
margin-right: 10px;
}
.each-user .circle {
background: #00BCD4;
}
.each-user .circle:last-child {
margin-right: 0;
}
/* Circle showing total */
.total-users {
padding: 0;
margin-bottom:
}
.total-users .circle {
background: #3F51B5;
margin: 0;
position: relative;
}
.total-users .circle .txt {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #fff;
}
<div class="container">
<div class="users-holder">
<div class="total-users">
<div class="circle">
<span class="txt">+12</span>
</div>
</div>
<div class="each-user">
<div class="circle user-circle"></div>
<div class="circle user-circle"></div>
<div class="circle user-circle"></div>
<div class="circle user-circle"></div>
<div class="circle user-circle"></div>
<!-- Sixth Circle -->
<div class="circle"></div>
</div>
</div>
</div>
Hope this helps!
I've used jQuery. See this https://jsfiddle.net/q86x7mjh/26/
HTML:
<div class="user-list-container">
<div class="total-circle hidden"><span></span></div>
<div class="user-circle"><span>T</span></div>
<div class="user-circle"><span>C</span></div>
<div class="user-circle"><span>U</span></div>
<div class="user-circle"><span>M</span></div>
<div class="user-circle"><span>R</span></div>
<div class="user-circle"><span>Z</span></div>
<div class="user-circle"><span>N</span></div>
<div class="user-circle"><span>O</span></div>
<div class="user-circle"><span>M</span></div>
<div>
jQuery:
var items_to_show = 5;
if($('.user-circle').length > items_to_show){
var hide = $('.user-circle').length - items_to_show;
for(var i = 0; i < hide; i++){
$('.user-circle').eq(i).addClass('hidden');
}
$('.total-circle').removeClass('hidden');
$('.total-circle span').text('+' + hide);
}
So after quite some time I have solved the problem. I am posting my answer here for anyone that will in the future experience a similar issue...
Have a good day!
I have added the following lines of code to my template:
return CardDataMembers.find({lkp_card_data_fkeyi_ref: cardDataId},{sort: {createdAt: -1}, limit: 3});
diffMembers(){
const instance = Template.instance();
const cardDataId = new Mongo.ObjectID(instance.data.cardData._id.valueOf());
const limit = 3;
const allMembersOnCard = CardDataMembers.find({lkp_card_data_fkeyi_ref: cardDataId}).count();
let remainingMembers = allMembersOnCard - limit;
return remainingMembers;
},
And in the HTML included:
<div class="other-profile" style="background-color:#dedede;">
<span>+{{diffMembers}}</span>
</div>

Categories