How to change order of elements in html using javascript - javascript

I am creating a simple game that has 9 divisions and each 8 of the divisions have a penguin hidden in them and the 9th one has a monster. Now my game works fine but what I want to do is every time I load the page, arrangement of the divisions should change so as to add randomness to the game.
Here is my code:
$(document).ready(function() {
//This code will run after your page loads
$('body').on('mousedown', '.yeti', function(event) {
alert("Yaaaarrrr!");
});
});
<div class="gameholder">
<div class="title"></div>
<div class="penguin1"></div>
<div class="penguin2"></div>
<div class="penguin3"></div>
<div class="penguin4"></div>
<div class="penguin5"></div>
<div class="penguin6"></div>
<div class="penguin7"></div>
<div class="penguin8"></div>
<div class="yeti"></div>
</div>
After adding images and some positioning to the div's this is how it looks

Keeping Your Animals Contained
Consider creating a container for all of your game elements as you only want to randomize their order as you don't want to get the title mixed up in all of this :
<div class='game-container'>
<div class="penguin1"></div>
<div class="penguin2"></div>
<div class="penguin3"></div>
<div class="penguin4"></div>
<div class="penguin5"></div>
<div class="penguin6"></div>
<div class="penguin7"></div>
<div class="penguin8"></div>
<div class="yeti">
</div>
Shuffling Them Around
This should make them easier to randomize through a simple jQuery extension function like this one mentioned in this related thread :
$.fn.randomize = function(selector){
(selector ? this.find(selector) : this).parent().each(function(){
$(this).children(selector).sort(function(){
return Math.random() - 0.5;
}).detach().appendTo(this);
});
return this;
};
You can combine these two approaches by then simply calling the following when your page has loaded :
$(document).ready(function(){
// Define your randomize function here
// Randomize all of the elements in your container
$('.game-container').randomize('div');
});
Example
$.fn.randomize = function(selector){
(selector ? this.find(selector) : this).parent().each(function(){
$(this).children(selector).sort(function(){
return Math.random() - 0.5;
}).detach().appendTo(this);
});
return this;
};
// Randomize all of the <div> elements in your container
$(".game-container").randomize('div');
.game-container { width: 300px; }
.penguin { background: url('http://vignette1.wikia.nocookie.net/farmville/images/b/be/Baby_Penguin-icon.png/revision/latest?cb=20110103080900'); height: 100px; width: 100px; display: inline-block; }
.yeti { background: url('http://www.badeggsonline.com/beo2-forum/images/avatars/Yeti.png?dateline=1401638613'); height: 100px; width: 100px; display: inline-block; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class='game-container'>
<div class='penguin'></div>
<div class='penguin'></div>
<div class='penguin'></div>
<div class='penguin'></div>
<div class='penguin'></div>
<div class='penguin'></div>
<div class='penguin'></div>
<div class='yeti'></div>
<div class='penguin'></div>
</div>

<body>
<div class="gameholder">
<div class="title"></div>
<div class="penguin1"></div>
<div class="penguin2"></div>
<div class="penguin3"></div>
<div class="penguin4"></div>
<div class="penguin5"></div>
<div class="penguin6"></div>
<div class="penguin7"></div>
<div class="penguin8"></div>
<div class="yeti"></div>
</div>
<script type="text/javascript">
$(document).ready( function() {
$('.gameholder div').shuffle();
/*
* Shuffle jQuery array of elements - see Fisher-Yates algorithm
*/
jQuery.fn.shuffle = function () {
var j;
for (var i = 0; i < this.length; i++) {
j = Math.floor(Math.random() * this.length);
$(this[i]).before($(this[j]));
}
return this;
};
//This code will run after your page loads
$('body').on('mousedown', '.yeti', function(event) {
alert("Yaaaarrrr!");
});
});
</script>
Here you would like to know what this 2 line of code is doing ->
j = Math.floor(Math.random() * this.length); // (1)
$(this[i]).before($(this[j])); // (2)
Here in line 1 first I am getting random number using Math.random, Math.random gives you floating number ranging from zero to one. so here I am multiplying that number with length, so it gives me random floating number from zero to length, now I am flooring this number to integer, to get integer from zero to length - 1
If we have a selector $('#b').before('#a') then it puts #a element before #b element, so here we are getting one by one element and putting them in the random order.

Related

Jquery append while wrapping every x element

I'm trying to create HTML like this:
<div class="container">
<div class="wrap">
<div class="el"></div>
<div class="el"></div>
<div class="el"></div>
</div>
<div class="wrap">
<div class="el"></div>
<div class="el"></div>
<div class="el"></div>
</div>
<div class="wrap">
<div class="el"></div>
<div class="el"></div>
<div class="el"></div>
</div>
</div>
The component used to add el element:
<input type="text" name="elements" />
el elements will appended to the container based on what number is added in the input. Every 3 elements should be wrapped in wrap div.
What I have so far:
$("input[name=elements]").on("keydown keyup", function() {
var amount = parseInt($(this).val());
for(i = 0; i < amount; i++) {
$(".container").append('<div class="el"></div>');
}
});
It adds the el divs but I'm not sure how to simultaneously wrap every 3 in wrap. Also is it possible to also remove el divs? If say I first type 8 in the input then I type 3, 11 divs will be added instead having just 3. In other words, the number of el divs in the HTML should alway be equal to the number in the input value. Would it make sense just to clear out the HTML first every time on input type?
You could first create an array of elements based on number of input value, append it to container and then wrap every nth element into wrap element.
const container = $('.container')
$("input").on('keyup', function() {
const val = parseInt($(this).val()) || 0;
const html = Array.from(Array(val), () => (
$("<div>", {
'class': 'el',
'text': 'element'
})
))
container.html(html)
for (let i = 0; i < val; i += 3) {
container
.find('.el')
.slice(i, i + 3)
.wrapAll("<div class='wrap'></div>");
}
})
.wrap {
border: 1px solid green;
margin: 10px 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text">
<div class="container"></div>

Shifting forward in an array when iterating over elements

I have repeating elements (section) on a page. I want to iterate the background colors of the elements between three colors that are held in a array. And within some of those elements I have text (p) that I want to iterate through those same colors, except I want it to be the next color in the array as the background.
So if I have an array that looks like ["111111", "222222", "333333"], I want the background color of the first section to be #111111 and the color of the first p to be #222222. Also there are more elements on the page than there are items in the array so we need to loop back through the array. The page when complete should look like:
<body>
<section style="background-color: #111111;">
<p style="color: #222222;">foo bar</p>
</section>
<section" style="background-color: #222222;">
<p style="color: #333333;">foo bar</p>
</section>
<section style="background-color: #333333;">
<!--no p in this one-->
</section>
<section style="background-color: #111111;">
<p style="color: #222222;">foo bar</p>
</section>
</body>
I have the background-color part done but I can't figure out how to shift to the next item in the array and start over at the first item when necessary.
var bgColors = ["111111", "222222", "333333"];
$('section').each(function(i) {
var bgColor = bgColors[i % bgColors.length];
$(this).css('background-color', '#'+bgColor);
// How to do text color???
$(this).find("p").css('color', ???);
});
The script should be flexible so you can add and change colors. Thanks.
EDIT: I realized I left out an important point which is that not every section has a p so you can't just iterate through them each independently. Also due to a c&p mishap my html didn't match my JS. Apologies.
Just use i+1 for the modulo for the foreground
It is the same logic you already apply for the bgColor, you just need to go one more for the foreground
var bgColors = ["red", "green", "blue", "yellow"];
$(function() {
$('.section').each(function(i) {
var bgColor = bgColors[i % bgColors.length];
var fgColor = bgColors[(i + 1) % bgColors.length];
$(this).css('background-color', bgColor);
$(this).find(".text").css('color', fgColor);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="section">
<div class="text">foo bar</div>
</div>
<div class="section">
<div class="text">foo bar</div>
</div>
<div class="section">
<div class="text">foo bar</div>
</div>
<div class="section">
<div class="text">foo bar</div>
</div>
You can have a logic like
var bgColorIndex = i % bgColors.length;
var bgColor = bgColors[i % bgColors.length];
$(this).css('background-color', '#'+bgColor);
var fgColor = bgColorIndex + 1 === bgColors.length ? bgColors[0] : bgColors[bgColorIndex + 1];
$(this).find("p").css('color', fgColor);
It checks if the next index is equal to the length, set the color to the first item, otherwise set to the next color by incrementing.
Code example
var bgColors = ['red', 'blue', 'green', 'yellow'];
$(document).ready(function() {
$('.section').each(function(i) {
var bgColorIndex = i % bgColors.length;
var bgColor = bgColors[i % bgColors.length];
$(this).css('background-color', bgColor);
var fgColor = bgColorIndex + 1 === bgColors.length ? bgColors[0] : bgColors[bgColorIndex + 1];
$(this).find(".text").css('color', fgColor);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div class="section">
<div class="text">foo bar</div>
</div>
<div class="section">
<div class="text">foo bar</div>
</div>
<div class="section">
<div class="text">foo bar</div>
</div>
<div class="section">
<div class="text">foo bar</div>
</div>
</body>
Do you specifically need to do this in JavaScript for some reason, or would a pure CSS solution be preferable? Because you can achieve the same effect with :nth-child():
.section:nth-child(3n+1) {
background-color: #111;
}
.section:nth-child(3n+1) .text {
color: #222;
}
.section:nth-child(3n+2) {
background-color: #222;
}
.section:nth-child(3n+2) .text {
color: #333;
}
.section:nth-child(3n+3) {
background-color: #333;
}
.section:nth-child(3n+3) .text {
color: #111;
}
More performant, no FOUC, works for people with JavaScript disabled, etc.
Codepen: https://codepen.io/anon/pen/aLyOwJ

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>

get element by id - using variable

I'm trying to use the function getElementById().
I have several ID's that i want to change style of, one by one, in an increasing order. I have a variable called numberOfTimes, which increases with 1 every time.
The names of the ID's are 1, 2, 3, 4 etc, and up to 8.
Is there some way I can use the variable-name in the function - if not, how should you solve this?
var numberOfTimes = 1;
document.getElementById(1).style.backgroundColor = "green";
Let's pretend your IDs look like this idx (x stands for the number). You can do:
var numberOfTimes = 8;
for (var i = 1; i <= numberOfTimes; ++i) {
document.getElementById('id' + i).style.backgroundColor = "green";
}
Solution if you really specific to change the color of the element one by one. Then you can use for loop.
second
document.getElementById(1)
You can use integer value directly but preferable you should use id with some text.
just use like this in for loop
for(var i=1;i<=8;i++){
document.getElementById("div_"+i).style.backgroundColor = "green";
}
As stated in other answers and comments, it is highly recommended not to use numbers only as IDs, also you can pick these divs upon a unique class name which will get you an array of them, and just loop through the array just like in this fiddle.
However here's the code JS Fiddle
var id = 1;
changeBG();
function changeBG() {
document.getElementById('el-' + id).style.backgroundColor = "green";
id++;
var t = setTimeout(changeBG, 500);
}
div {
width: 100%;
height: 50px;
margin-bottom: 5px;
display: inline-block;
}
<div id="el-1"></div>
<div id="el-2"></div>
<div id="el-3"></div>
<div id="el-4"></div>
<div id="el-5"></div>
<div id="el-6"></div>
<div id="el-7"></div>
<div id="el-8"></div>
Numbers-only ID are not a good practice, I hope this quetion is in the purpose of learning.
for(var i = 1; i < 9; i++){
document.getElementById(i).style['background'] = 'green';
}
div {
width:100%;
height:20px;
margin-bottom:10px;
}
<div id="1"></div>
<div id="2"></div>
<div id="3"></div>
<div id="4"></div>
<div id="5"></div>
<div id="6"></div>
<div id="7"></div>
<div id="8"></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