Dynamically arranging divs using jQuery - javascript

I have the following structure:
<div id="container">
<div id="someid1" style="float:right"></div>
<div id="someid2" style="float:right"></div>
<div id="someid3" style="float:right"></div>
<div id="someid4" style="float:right"></div>
</div>
Now someid is acually a unique id for that div. Now i receive an array which has a different order say someid 3,2,1,4, then how do i move these divs around to match the new order using jQuery?
Thankyou very much for your time.

My plugin version - Working Demo
Takes an array and optional id prefix and reorders elements whose ids correspond to the order of (id prefix) + values inside the array. Any values in the array that don't have an element with the corresponding id will be ignored, and any child elements that do not have an id within the array will be removed.
(function($) {
$.fn.reOrder = function(array, prefix) {
return this.each(function() {
prefix = prefix || "";
if (array) {
for(var i=0; i < array.length; i++)
array[i] = $('#' + prefix + array[i]);
$(this).empty();
for(var i=0; i < array.length; i++)
$(this).append(array[i]);
}
});
}
})(jQuery);
Code from the demo
jQuery
$(function() {
$('#go').click(function() {
var order = $('#order').val() == ""? null: $('#order').val().split(",");
$('#container').reOrder(order, 'someid');
});
});
(function($) {
$.fn.reOrder = function(array, prefix) {
return this.each(function() {
prefix = prefix || "";
if (array) {
for(var i=0; i < array.length; i++)
array[i] = $('#' + prefix + array[i]);
$(this).empty();
for(var i=0; i < array.length; i++)
$(this).append(array[i]);
}
});
}
})(jQuery);
HTML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<title>reOrder Demo</title>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css" media="screen">
body { background-color: #fff; font: 16px Helvetica, Arial; color: #000; }
div.style { width: 200px; height: 100px; border: 1px solid #000000; margin: 5px; }
</style>
</head>
<body>
<div id="container">
<div id="someid1" class="style" style="background-color:green;">div1</div>
<div id="someid2" class="style" style="background-color:blue;">div2</div>
<div id="someid3" class="style" style="background-color:red;">div3</div>
<div id="someid4" class="style" style="background-color:purple;">div4</div>
</div>
<p>Pass in a comma separated list of numbers 1-4 to reorder divs</p>
<input id="order" type="text" />
<input id="go" type="button" value="Re-Order" />
</body>
</html>

[Edit], This is tested and works:
var order = [3,2,1,4];
var container = $("#container");
var children = container.children();
container.empty();
for (var i = 0; i < order.length; i++){
container.append(children[order[i]-1])
}
The i-1 is necessary since your ordering starts at 1 but arrays are indexed from 0.
Thanks to J-P and Russ Cam for making me look at it again.

Here's a jQuery-less solution:
function appendNodesById(parent, ids) {
for(var i = 0, len = ids.length; i < len; ++i)
parent.appendChild(document.getElementById(ids[i]));
}
appendNodesById(document.getElementById('container'),
['someid4', 'someid2', 'someid3', 'someid1']);

If you have all the content in the array then remove all the content from the wrapper div container in your code. then start adding the received divs one by one:
var v = $(ar[0]).append(ar[1]).append(ar[2]);
$("#container").html(v);
If this does not works then look into this thread that discusses about positioning elements relative to other elements.

Related

'querySelector' on 'Document' is not a valid selector error raised even though id's of divs seem fine [duplicate]

This question already has answers here:
Using querySelector with IDs that are numbers
(9 answers)
Closed 2 years ago.
I am trying to add styles via Javascript. For some reason unknown to me, I am getting an error that says my query selector is not a valid selector, even though my ids look correct. Can someone please help me to understand what is going wrong with my code?
var currentRow;
var rowCol;
for(let i = 0; i < 3; i++)
{
var x = i.toString();
currentRow = document.querySelector("#0");
for(let j = 0; j < 3; j++)
{
y = j.toString();
rowCol = currentRow.querySelector("#" + x + y);
if(i == 1)
{
rowCol.style.border = "5px 'solid black'";
rowCol.style.border = "5px 'solid black'";
}
if(j == 0 || j == 1)
{
rowCol.style.border = "5px 'solid black'";
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="./tictactoe.css">
</head>
<body>
<script src="tictactoe.js"></script>
<div class= "header">
</div>
<div class= "main">
<div id = '0'>
<div id = "00">x</div>
<div id = "01">x</div>
<div id = "02">x</div>
</div>
<div id = "1">
<div id = "10">x</div>
<div id = "11">x</div>
<div id = "12">x</div>
</div>
<div class = "2">
<div id = "20">x</div>
<div id = "21">x</div>
<div id = "22">x</div>
</div>
</div>
</body>
</html>
Your script is included in the head and executed before the body of the HTML document is parsed, so the elements don't exist yet. Move the script to just before the closing body tag.
Then, use .getElementById() to access your elements that have numbers as the first character in their id. .querySelector() won't work on those ids.
Also, your CSS is incorrect. Instead of:
"5px 'solid black'"
It should be:
"5px solid black"
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="./tictactoe.css">
</head>
<body>
<div class= "header"></div>
<div class= "main">
<div id = '0'>
<div id = "00">r1c1</div>
<div id = "01">r1c2</div>
<div id = "02">r1c3</div>
</div>
<div id = "1">
<div id = "10">r2c1</div>
<div id = "11">r2c2</div>
<div id = "12">r3c3</div>
</div>
<div class = "2">
<div id = "20">r3c1</div>
<div id = "21">r3c2</div>
<div id = "22">r3c3</div>
</div>
</div>
<!-- With the script here, all the HTML above will be parsed
and in memory so you can access the elements. -->
<script src="tictactoe.js"></script>
<script>
var currentRow;
var rowCol;
for(let i = 0; i < 3; i++){
var x = i.toString();
currentRow = document.getElementById("0");
for(let j = 0; j < 3; j++){
y = j.toString();
rowCol = document.getElementById(x + y);
if(i == 1){
rowCol.style.border = "5px solid black";
rowCol.style.border = "5px solid black";
}
if(j == 0 || j == 1){rowCol.style.border = "5px solid black";}
}
}
</script>
</body>
</html>

Apply a JavaScript function to all Array elements except the ith element

In one of my projects I made 3 galleries, I would like to put both of them on the same page in the same position, not at the same time, however. For this to be possible, I chose to create 3 buttons. When I click on the first button for example, the first gallery should appear (both galleries are initially on display:none), then when I click on the second button, the second one should appear and the one shown before should disappear, and so for each of the galleries. I made a simplified copy of the page to make the thinking easier.
In general, my problem is that I don't quite know how to apply a function to all the elements in an Array except for one element.
Here is the code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Galleries</title>
<link rel="stylesheet" type="text/css" href="gs.css">
<style type="text/css">
body{
background-color:royalblue;
}
header{
text-align: center;
}
article{
width:95%;
margin:auto 2.5% auto 2.5%;
height:850px;
background-color:tomato;
display:none;
}
</style>
</head>
<body>
<header>
<button>Third Gallery</button>
<button>Second Gallery</button>
<button>Third Gallery</button>
</header>
<section>
<article>
<h1>This is the first gallery</h1>
</article>
<article>
<h1>This is the second gallery</h1>
</article>
<article>
<h1>This is the third gallery</h1>
</article>
</section>
<script type="text/javascript">
var button=document.getElementsByTagName('button');
var gallery=document.getElementsByTagName('article');
for(var i=0; i<button.length; i++){
(function(index){
button[index].onclick=function(){
gallery[index].style.display="block";
}
}(i));
}
</script>
</body>
</html>
You could iterate over all the elements and compare the index of the button with the index of the current gallery item:
[].forEach.call(gallery, function (el, i) {
el.style.display = i === index ? 'block': 'none';
});
or:
for (var i = 0; i < gallery.length; i++) {
gallery[i].style.display = i === index ? 'block': 'none';
}
This will loop over all the elements and set the display of each element to none except for the on with an index that corresponds to the clicked button.
Example Here
var button = document.getElementsByTagName('button');
var gallery = document.getElementsByTagName('article');
for (var i = 0; i < button.length; i++) {
(function(index) {
button[index].onclick = function() {
[].forEach.call(gallery, function (el, i) {
el.style.display = i === index ? 'block': 'none';
});
}
}(i));
}
What you have done is almost right... Loop through the whole thing and when the particular element comes, do not do that, but I don't understand what's the use of closure here:
var button=document.getElementsByTagName('button');
var gallery=document.getElementsByTagName('article');
for(var i=0; i<button.length; i++){
if (i != 2) // Make sure `i` is not equal to 2.
(function(index){
button[index].onclick=function(){
gallery[index].style.display="block";
}
}(i));
}

Push numbers into array on click event

I'm trying to build a calculator and at this point, need to "collect" any numbers that get clicked in an array. Right now I'm unsure of where to build that array (should it be in a different function all together?). I think I'll need to use .push(), but know I need to use it on an array and am not sure where to define that. When I console.log(gridItems), clearly I get everything, but only want the numbers...
/*Calculator
function add(n, x) {
return n + x;
}
console.log(add(3, 8));
function subtract(n, x) {
return n - x;
}
console.log(subtract(3, 8));
function multiply(n, x) {
return n * x;
}
console.log(multiply(3, 8));
function divide(n, x) {
return n / x;
}
console.log(divide(3, 8));*/
// console.log number when button is clicked
function getValue(e){
var divValue = parseInt(e.target.textContent);
console.log(divValue);
}
function numberTrack() {
var gridItems = document.getElementsByClassName('grid');
for (var i = 0; i < gridItems.length; i ++) {
gridItems[i].onclick = getValue;
}
}
numberTrack();
#grid-container {
width: 200px;
}
.grid {
width: 50px;
height: 50px;
display: inline-block;
text-align: center;
}
.gray {
background-color: #ccc;
}
.pink {
background-color: pink;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
<div id="grid-container" data-value="1">
<div class="grid gray">0</div>
<div class ="grid pink">1</div>
<div class="grid gray">2</div>
<div class ="grid pink">3</div>
<div class="grid gray">4</div>
<div class ="grid pink">5</div>
<div class="grid gray">6</div>
<div class ="grid pink">7</div>
<div class="grid gray">8</div>
<div class ="grid pink">9</div>
</div>
</head>
<body>
</body>
</html>
You can define it in global scope like this:
var clickedNumbers = []
function getValue(e) {
var divValue = parseInt(e.target.textContent);
clickedNumbers.push(divValue);
}
function numberTrack() {
var gridItems = document.getElementsByClassName('grid');
for (var i = 0; i < gridItems.length; i++) {
gridItems[i].onclick = getValue;
}
}
numberTrack();
Then push clicked number to array clickedNumbers by clickedNumbers.push(divValue)

JQuery Remove not removing specified div

I have a small page on which you can add squares of different colors to a div with a button. After adding them, you can remove them by double clicking any of the squares created.
My code works well, when adding elements. However when I want to remove a square, I just get to remove one and after that I can´t make the element disappear on HTML even though the counter does decrease. I´m a doing something wrong with the remove() function? Right now I´m just focusing on the blue (Azul) color.
Here´s my code
https://jsfiddle.net/kdwyw0mc/
var azules = 0;
var rojos = 0;
var amarillos = 0;
var verdes = 0;
function eliminar(cuadro){
azules = parseInt(jQuery('#num-azules').text());
verdes = parseInt(jQuery('#num-verdes').text());
rojos = parseInt(jQuery('#num-rojos').text());
amarillos = parseInt(jQuery('#num-amarillos').text());
if(cuadro[0].classList[1]=='blue'){
azules = azules -1;
}
else if(cuadro[0].classList[1]=='red'){
rojos--;
}
else if(cuadro[0].classList[1]=='yellos'){
amarillos--;
}
else if(cuadro[0].classList[1]=='green'){
verdes--;
}
cuadro.remove();
jQuery('#num-azules').text(azules);
jQuery('#num-verdes').text(verdes);
jQuery('#num-rojos').text(rojos);
jQuery('#num-amarillos').text(amarillos);
}
function agregar(){
jQuery('span#num-azules').val(azules);
var numCuadros = jQuery("#numero").val();
var color = $('#color option:selected').text();
for( i = 0; i< numCuadros; i++){
if(color=='Azul'){
/*jQuery(".square").append(function(){
return jQuery('<div class="square blue"> </div>').ondblclick(eliminar);
})*/
var newSquare = jQuery('<div class="square blue"> </div>')
var a = jQuery(".squares").append(newSquare);
newSquare.dblclick(function(){eliminar(newSquare);})
azules += 1;
}
else if(color=='Rojo'){
jQuery(".squares").append('<div class="square red"> </div>')
rojos+= 1;
}
else if(color=='Amarillo'){
jQuery(".squares").append('<div class="square yellow"> </div>')
amarillos+= 1;
}
else if(color=='Verde'){
jQuery(".squares").append('<div class="square green"> </div>')
verdes+= 1;
}
}
jQuery('#num-azules').text(azules);
jQuery('#num-verdes').text(verdes);
jQuery('#num-rojos').text(rojos);
jQuery('#num-amarillos').text(amarillos);
}
/*
* jQuery("#agregar").click(function(){
agregar();
});
VS
jQuery("#agregar").click(agregar());
* */
jQuery('#num-azules').text(azules);
jQuery('#num-verdes').text(verdes);
jQuery('#num-rojos').text(rojos);
jQuery('#num-amarillos').text(amarillos);
jQuery("#agregar").click(function(){
agregar();
});
HTML:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="styles/reset.css"/>
<link rel="stylesheet" href="styles/main.css"/>
</head>
<body>
<div class="main-content">
<div class="toolbar">
Numero Cuadrados: <input id="numero"type="text"/>
<select id="color" name="color">
<option value="azul">Azul</option>
<option value="rojo">Rojo</option>
<option value="amarillo">Amarillo</option>
<option value="verde">Verde</option>
</select>
<button id="agregar">Agregar</button>
</div>
<div class="squares">
</div>
<div class="numeros">
<p>Azules: <span id="num-azules">0</span> </p>
<p>Rojos: <span id="num-rojos">0</span></p>
<p>Verde: <span id="num-verdes">0</span></p>
<p>Amarillo: <span id="num-amarillos">0</span></p>
</div>
</div>
<script src="scripts/jquery-1.11.3.min.js"></script>
<script src="scripts/main.js"></script>
</body>
</html>
This is an inefficient way of registering / listening to events, it is better to delegate the event handling to a wrapper (parent) container:
$("#container").on("dblclick", ".square", function(){
$(this).remove();
)};
on works for dynamically created elements; since the container was already in the DOM, it can continue listening to events coming from any other, newly created child element that has class .square.
http://api.jquery.com/on/
Edit:
One way of solving the counter problem would be to do something like this:
var StateObj = function(){
this.counter = 0;
this.arrSquares = [];
this.increaseCounter = function(){
this.counter += 1;
},
this.decreaseCounter = function(){
this.counter -= 1;
},
this.addSquare = function(id, color){
this.arrSquares.push({id: id, color: color});
},
this.getSquareById = function(id){
return square = $.grep(this.arrSquares, function(){ return id == id; });
}
}
var stateObj = newStateObj();
$("#container").on("dblclick", ".square", function(e){
$(this).remove();
var id = $(e.currentTarget).attr("id");
stateObj.increaseCounter();
console.log(stateObj.counter);
)};

Clear a div tag that is refilled with a table created by JavaScript

My page is used to create a base-6 table of numbers that highlight prime numbers. The user inputs the number that they want the table to end in, and a script generates the table. It does it in a div tag with the id "tablearea."
The problem is that if the user inputs a new number and submits, the second table is added at the bottom of the first. What I want is for the first table to be cleared, and subsequent requested tables to be written in the same area. How do I accomplish this?
<!DOCTYPE HTML>
<html lang="en">
<!-- This page asks the user to input a number to search for primes and returns a base-6 table with primes highlighted -->
<head>
<meta charset="utf-8">
<meta name="keywords" content="prime numbers, prime, primes, prime twins">
<title>Prime Numbers</title>
<script type="text/javascript">
/* This function determines if a number is prime or not */
function isPrime(n) {
if (isNaN(n) || !isFinite(n) || n%1 || n<2) return false;
if (n%2==0) return (n==2);
if (n%3==0) return (n==3);
var m=Math.sqrt(n);
for (var i=5;i<=m;i+=6) {
if (n%i==0) return false;
if (n%(i+2)==0) return false;
}
return true;
}
/* This function creates the table and color codes the cells of prime numbers */
function tableCreate(X){
var numCheck = X;
var numRow = numCheck/6;
var numCell = 1;
var body = document.body;
var tbl = document.createElement('table');
for(var i = 0; i < numRow; i++){
var tr = tbl.insertRow(-1);
for(var j = 0; j < 6; j++){
if(i==numRow && j==6 || numCheck==numCell-1){
break
}
else {
var td = tr.insertCell(-1);
if(isPrime(numCell) == true){
td.style.backgroundColor='yellow';
}
td.appendChild(document.createTextNode(numCell));
numCell++;
}
}
}
body.appendChild(tbl).tablearea;
}
</script>
<style type="text/css">
<!-- td {border: 1px solid black} -->
table{width: 50%; border: 1px solid black; margin-left: auto; margin-right: auto}
</style>
</head>
<body>
<form name="primes">
<p style="text-align: center">How many numbers would you like to check for primes?
<input type="text" id="nums">
<input type="button" value="Check'em!" onClick="tableCreate(document.primes.nums.value)">
<input type="reset">
</p>
</form>
<br /><br /><br /><br />
<div id="tablearea">
</div>
</body>
</html>
You need to flush the contents of the div before you insert a table with different content to the same div
Just replace the below line in your code
body.appendChild(tbl).tablearea;
with
document.getElementById("tablearea").innerHTML='';
document.getElementById("tablearea").appendChild(tbl);
If you want the table to appear in the div with ID tablearea, you need to do something like:
var div = document.getElementById('tablearea');
div.appendChild(tbl);
If you then want to replace the table with a new one, there are lots of options, but the easiest is probably to empty the div and insert the new table:
div.innerHTML = '';
div.appendChild(tbl);
If you have other content in the div that you don't want to destroy, then replace just the table:
var oldTable = div.getElementsByTagName('table')[0];
// If there's an existing table, replace it
if (oldTable) {
div.replaceChild(tbl, oldTable);
// If there wasn't, just append the new one
} else {
div.appendChild(tbl);
}

Categories

Resources