I have the current HTML:
<div id="1-1">TITLE1</div>
<div id="1-2">TITLE2</div>
<div id="1-3">TITLE3</div>
<div id="1-4">TITLE4</div>
<div id="1-5">TITLE5</div>
<div class="topic">A1</div>
<div class="topic">B2</div>
<div class="topic">C3</div>
<div class="topic">D4</div>
<div class="topic">E5</div>
<div class="topic">F6</div>
<div class="topic">G7</div>
<div class="topic">H8</div>
<div class="topic">I9</div>
<div class="topic">J10</div>
<div class="topic">K11</div>
<div class="topic">L12</div>
<div class="topic">M13</div>
<div class="topic">N14</div>
<div class="topic">O15</div>
And I want to use JavaScript to create a for loop that will append the correct .topic nodes into the correct TITLE div based on this object:
all = {'1-1': ['A', 'B', 'C'],
'1-2': ['D'],
'1-3': ['E', 'F', 'G', 'H'],
'1-4': ['I', 'J'],
'1-5': ['K', 'L', 'M', 'N', 'O']
};
Where the loop will ideally result in:
<div id="1-1">TITLE1
<div class="topic">A1</div>
<div class="topic">B2</div>
<div class="topic">C3</div>
</div>
<div id="1-2">TITLE2
<div class="topic">D4</div>
</div>
<div id="1-3">TITLE3
<div class="topic">E5</div>
<div class="topic">F6</div>
<div class="topic">G7</div>
<div class="topic">H8</div>
</div>
<div id="1-4">TITLE4
<div class="topic">I9</div>
<div class="topic">J10</div>
</div>
<div id="1-5">TITLE5
<div class="topic">K11</div>
<div class="topic">L12</div>
<div class="topic">M13</div>
<div class="topic">N14</div>
<div class="topic">O15</div>
</div>
I've taken a stab at this by creating two arrays -- one of the "TITLE*" locations in all and another of how many "topics" should be in each slice
let header_position = [0,4,6,11,14]
let topics_between = [3,1,4,2,5]
I was trying to leverage this and find a pattern for the for loop so that I can use these array numbers in order to put things in the right place but I can't seem to figure out the proper loop. Any help would be appreciated:
Attempted Solution
for (i = 0; i < header_position.length; i++) {
// i = 0 topics.slice(0,2)
// i = 2 topics.slice(3,3)
// i = 3 topics.slice(4,7)
// i = 4 topics.slice(8,9)
// i = 5 topics.slice(10,14)
let currentslice = topics.slice(header_position[i] + 1, header_position[i + 1] - 2)
if (i === 0) {
currentslice = topics.slice(0, topics_between[i] - 1)
}
console.log(currentslice)
currentslice.appendTo("#1-" + [i + 1])
}
This loop does not work as it stands, but I would appreciate any help or considerations in trying to get this logic functional!
Your question seems pretty theorical... And looks like an XY problem to me.
I assume your titles certainly will not be TITLE1, TITLE2 and so on with some real content.
I suppose you managed to define the all array to have a start of organisation of your page... But from what's posted, I can't suggest any better way.
So if I just take the all and the header_position arrays as-is, the loop would use two indexes, one for the headers and one for the topics.
Have a look below and tell me if that answers your theorical question as well as your concrete need.
let all = [ "TITLE1", "A", "B", "C",
"TITLE2", "D",
"TITLE3", "E", "F", "G", "H",
"TITLE4", "I", "J",
"TITLE5", "K", "L", "M", "N", "O"]
let header_position = [0,4,6,11,14]
//let topics_between = [3,1,4,2,5] // not used
let headerIndex = -1
let topicIndex = 0
for(i=0;i<all.length;i++){
if(header_position.indexOf(i)>-1){
headerIndex++
continue
}
$(".header").eq(headerIndex).append($(".topic").eq(topicIndex))
topicIndex++
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="header" id="1-1">TITLE1</div>
<div class="header" id="1-2">TITLE2</div>
<div class="header" id="1-3">TITLE3</div>
<div class="header" id="1-4">TITLE4</div>
<div class="header" id="1-5">TITLE5</div>
<div class="topic">A1</div>
<div class="topic">B2</div>
<div class="topic">C3</div>
<div class="topic">D4</div>
<div class="topic">E5</div>
<div class="topic">F6</div>
<div class="topic">G7</div>
<div class="topic">H8</div>
<div class="topic">I9</div>
<div class="topic">J10</div>
<div class="topic">K11</div>
<div class="topic">L12</div>
<div class="topic">M13</div>
<div class="topic">N14</div>
<div class="topic">O15</div>
From what I have understood, you want it to be split up by title. You can do this:
let count = 0;
for (let i = 0; i < all.length; i++) {
if (all[i].includes("TITLE")) {
let element = document.createElement("div");
element.innerHTML = all[i];
element.id = `1-${count + 1}`;
document.body.appendChild(element);
count++;
} else {
let element = document.createElement("div");
element.className = "topic";
element.innerHTML = `${all[i]}${i - count + 1}`;
document.getElementById(`1-${count}`).appendChild(element);
}
}
Let me know if it works.
Related
I have an array of js objects, and for every object in array I am trying to create a div with a template, designated with <template></template>. I am trying to do this using a for loop. The for loop does exactly what I want, one time.
Here is my HTML template to be copied:
<template id="tracktemp">
<div class="trackerItem">
<div class="itemNameTextCont">
<p class="itemNameText">Combatant Name</p>
</div>
<div class="itemHpTextCont">
<p class="itemHpText">HP 100</p>
</div>
<div class="itemApTextCont">
<p class="itemApText">AP 30</p>
</div>
<div class="itemActionButtonsCont">
<div class="actionButtonCont"><button class="actionButton">Heal</button></div>
<div class="actionButtonCont"><button class="actionButton">Dam</button></div>
<div class="actionButtonCont"><button class="actionButton">Stat</button></div>
<div class="actionButtonCont"><button class="actionButton">Abil</button></div>
</div>
<div class="itemModifyButtonsCont">
<div class="modifyButtonCont"><button class="modifyButton">Edit</button></div>
<div class="modifyButtonCont"><button class="modifyButton">Remove</button></div>
</div>
</div>
</template>
The HTML Section it's being copied into (within trackerCont)
<section class="trackerModule">
<div class="trackerModuleCont">
<div class="trackerHeaderCont">
<h2 class="trackerHeader">Combatants</h2>
</div>
<div class="trackerTopButtonsCont">
<div class="topButtonCont"><button class="topButton">Add</button></div>
<div class="topButtonCont"><button class="topButton">Add From</button></div>
</div>
<div id="trackerCont" class="trackerCont">
</div>
<div class="trackerBottomButtonsCont">
<div class="bottomButtonCont"></div>
<div class="bottomButtonCont"></div>
</div>
</div>
</section>
And the JS doing the copying
var trackerArray = [
{Name: "Joe Brown", HP: 100, AP: 30},
{Name: "Steve Smith", HP: 100, AP: 30},
{Name: "Jane", HP: 100, AP: 30}
]
function buildTracker() {
var trackerLength = trackerArray.length;
var trackItemTemp = document.getElementById('tracktemp').content.cloneNode(true);
for (i = 0; i < trackerLength; i++) {
var combatant = trackerArray[i];
var itemParent = document.getElementById('trackerCont');
trackItemTemp.querySelector('.itemNameText').innerText = combatant.Name;
trackItemTemp.querySelector('.itemHpText').innerText = combatant.HP;
trackItemTemp.querySelector('.itemApText').innerText = combatant.AP;
document.createElement(trackItemTemp);
}
}
I understand to some extent that appendChild can only create one element. I should be using document.createElement instead, no? I do not understand how to go about rewriting the code to copy the HTML template using createElement... If someone could lend me a hand that would be great! Thanks!
From
document.createElement(trackItemTemp);
To
document.getElementById("trackerCont").appendChild(trackItemTemp);
(edit)
I missed whole function code and i also missed there was a variable itemParent so I edited the last line of the function. Make sure to use cloneNode in each loop.
function buildTracker() {
var trackerLength = trackerArray.length;
var trackItem;
for (i = 0; i < trackerLength; i++) {
var trackItemTemp = document.getElementById('tracktemp').content.cloneNode(true);
var combatant = trackerArray[i];
var itemParent = document.getElementById('trackerCont');
trackItemTemp.querySelector('.itemNameText').innerText = combatant.Name;
trackItemTemp.querySelector('.itemHpText').innerText = combatant.HP;
trackItemTemp.querySelector('.itemApText').innerText = combatant.AP;
itemParent.appendChild(trackItemTemp);
}
}
So I am making a hangman game using plain javascript. I have gotten to the point of checking the letters that correspond to the selected word. In the checkLetter function, I am trying to find if an element(letter) exists in the array or not and then update the array. With the specified element, the setAttribute will update the value or a new attribute will be added with the specified name and value. In the console logs, it says null and means that it does not exist yet. I dynamically created a button in the js but I don't know why it's not recognizing the setAttribute. I hope I am clear enough. Looking for some input, thanks.
window.onload = function() {
const redoButton = document.getElementById("reset");
const displayLetter = document.getElementById("answer-input");
const placeLetters = document.getElementById("letter-input")
const revealWord = document.getElementById("revealword");
const healthBar = document.getElementById("lives");
const keyboardBtn = document.getElementById("keyboard")
//variables needed
let lives = 8;
let currentWord = [];
let randomWord = '';//generates word from list
let letterGuess = [];
let lettersInWord;
let emptySlots = 0;
let alphabet = ["A", "B", 'C', 'D', "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
const words = [
"Portland", "Berlin", "Boston", "Manchester",
"Sevilla", "Madrid", "Medellin", "Houston",
"Portland", "Miami", "Paris", "Cordoba"
]
//keyboard added dynamically
function createButtons() {
for (let i = 0; i < alphabet.length; i++) {
let buttons = document.createElement("button");
buttons.innerHTML =
`<button
id = ${alphabet[i]}
class="btn btn-primary"
button type="button"
onClick = "checkLetter(this.id)"
>
${alphabet[i]}
</button>`;
keyboardBtn.appendChild(buttons)
}
}
createButtons();
//check letter of chosen word, if its there or not
//SETATTRIBUTE is where the error is coming from
const checkLetter = function (id) {
let click = document.getElementById(id);
console.log(click);
//console.log(id);
for (let i = 0; i < emptySlots; i++) {
//check if letter is in array
if (currentWord.indexOf(id) === -1) {
currentWord.push(id);//push letter into currentWord
} else if (currentWord.indexOf(id) > -1) {
return null //already exists in array
}
}
document.getElementById(id).setAttribute("disabled", true)
console.log(id)
}
checkLetter();
//select random word from word array
function chosenWord() {
//choses random word from array
randomWord = words[Math.floor(Math.random() * words.length)];
console.log(randomWord);
//letters split up in array
lettersInWord = randomWord.split("");
console.log(lettersInWord)
emptySlots = lettersInWord.length;
for (let i = 0; i < emptySlots; i++) {
currentWord.push("-")
}
console.log(currentWord);
placeLetters.innerHTML = currentWord.join(" ");
}
chosenWord()
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/css/bootstrap.min.css"
integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css">
<title>Hangman 2021</title>
</head>
<body>
<!--header-->
<header class="container-fluid bg-success text-dark">
<div>
<span>
<h1 class="text-center">Hang that man</h1>
</span>
</div>
</header>
<div class="container">
<br>
<h3>Please choose a letter on your keyboard to reaveal the secret word</h3>
<br>
<!--each letter will display after all lives are gone-->
<div id="keyboard"></div>
<br>
<br>
<!--choices will be inserted here-->
<div id="answer-input">
<p id="letter-input">_</p>
</div>
<!--number of lives will be tracked here-->
<p id="lives">You have 8 lives left</p>
<!--everytime a guess is wrong, a limb is added to animation-->
<section class="animation">
<div class="justify-content-center">
<canvas id="gallows" width="300" height="150" style="border:1px solid #d3d3d3"></canvas>
</div>
<button id="reset">Play Again</button>
</section>
<br>
</div>
<!--footer-->
<footer class="container-fluid bg-success text-dark">
<div class="justify-content-center">Hang that man © 2021</div>
<div class="social justify-content-center">
<i class="fab fa-linkedin"></i>
|
<i class="fab fa-github"></i>
</div>
<div class="github">
<a>Andres Ramirez</a>
</div>
</footer>
<script src="index.js"></script>
</body>
</html>
I have a tag like below:
<section id="sec">
<div id="item1">item1</div>
<div id="item2">item2</div>
<div id="item3">item3</div>
<div id="abcitem1">abcitem1</div>
</section>
I want to check how many div tags contextText start with item. May I know is there any easier way that writes for condition and count them one by one(like Jquery)?
Use .filter() to filtering selected elements and use regex in .match() to check existence of item in element text.
var count = $("#sec div").filter(function(){
return $(this).text().match(/^item/);
}).length;
console.log(count);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section id="sec">
<div id="item1">item1</div>
<div id="item2">item2</div>
<div id="item3">item3</div>
<div id="abcitem1">abcitem1</div>
</section>
var res=0;
$( "#sec div" ).each(function( index ) {
var str= $(this).text() ;
if(str.startsWith("item")==true){
res++;
}
});
console.log(res); //returns 3
You could use reduce function to get the occurrence of elements which start with 'item'.
This is a native javascript solution, which uses startsWith, so you do not have to mess around with regular expressions.
var childDivs = document.getElementById('sec')
.getElementsByTagName('div');
var counter = Array.from(childDivs)
.reduce((accumulator, currentValue) => {
if (currentValue.innerHTML.startsWith('item')) {
return accumulator = accumulator + 1;
}
return accumulator;
}, 0);
console.log( counter );
<section id="sec">
<div id="item1">item1</div>
<div id="item2">item2</div>
<div id="item3">item3</div>
<div id="abcitem1">abcitem1</div>
</section>
Without any jQuery or regex
var nodes = document.querySelectorAll('#sec div')
var count = 0
nodes.forEach(node => count += node.innerText.startsWith('item'))
console.log(count)
<section id="sec">
<div id="item1">item1</div>
<div id="item2">item2</div>
<div id="item3">item3</div>
<div id="abcitem1">abcitem1</div>
</section>
it's possible to add booleans to a number, true means 1 and false means 0
Here is a pure JS way to count it.
function checkItemsCount(section) {
if (!section) return 0;
const sec = document.querySelector(section);
const items = sec.querySelectorAll('div');
let count = 0;
for (let i = 0; i < items.length; i++) {
if (/^item/.test(items[i].innerText)) count++;
}
return count;
}
console.log(checkItemsCount('#sec'));
<section id="sec">
<div id="item1">item1</div>
<div id="item2">item2</div>
<div id="item3">item3</div>
<div id="abcitem1">abcitem1</div>
</section>
I have looked and haven't found any solutions to my issue.
I have a grid like a puzzle.
<div id="grid-container">
<div class="item" id="item1"></div>
<div class="item" id="item2"></div>
<div class="item" id="item3"></div>
<div class="item" id="item4"></div>
<div class="item" id="item5"></div>
<div class="item" id="item6"></div>
<div class="item" id="item7"></div>
<div class="item" id="item8"></div>
<div class="item" id="item9"></div>
<div class="item" id="item10"></div>
<div class="item" id="item11"></div>
<div class="item" id="item12"></div>
<div class="item" id="item13"></div>
<div class="item" id="item14"></div>
<div class="item" id="item15"></div>
<div class="item" id="item16"></div>
<div class="item" id="item17"></div>
<div class="item" id="item18"></div>
<div class="item" id="item19"></div>
<div class="item" id="item20"></div>
<div class="item" id="item21"></div>
<div class="item" id="item22"></div>
<div class="item" id="item23"></div>
<div class="item" id="item24"></div>
<div class="item" id="item25"></div>
<div class="item" id="item26"></div>
<div class="item" id="item27"></div>
<div class="item" id="item28"></div>
<div class="item" id="item29"></div>
<div class="item" id="item30"></div>
<div class="item" id="item31"></div>
<div class="item" id="item32"></div>
<div class="item" id="item33"></div>
<div class="item" id="item34"></div>
<div class="item" id="item35"></div>
<div class="item" id="item36"></div>
</div>
and I have an array of what I want to fill the puzzle with:
var ws = [
['A', 'P', 'P', 'L', 'E', 'P'],
['A', 'G', 'C', 'A', 'A', 'I'],
['A', 'R', 'A', 'A', 'A', 'Z'],
['A', 'A', 'A', 'A', 'T', 'Z'],
['P', 'P', 'A', 'A', 'A', 'A'],
['A', 'E', 'P', 'R', 'A', 'Y']
];
I have also created class to print out the array.
class Puzzle {
constructor(width, height) {
this.width = (width)? width : 6;
this.height = (height)? height : 6;
if(this.width != this.height)
throw "height and width must be the same"
}
print(){
console.log(ws)
}
}
puz = new Puzzle(6, 6);
puz.print();
What I want to do is to pass the output of the array into each div with IDs: item1..36.
I have used
document.getElementById('myArray').innerHTML = ws;
to try to get it to work but its not working. Please I need a better approach to it.
You may try this inside your print function. (my guess is your print will update the UI)
print() {
for(var i =1 ; i<= this.height; i++){
for(var j = 1; j <= this.width; j++) {
document.getElementById(`item${(i-1) * this.height + j}`).innerHTML = ws[i-1][j-1];
}
}
}
Hope this will help!
you need to create a matrix on the contructor,
class Puzzle {
constructor(width, height) {
var ws = [
['A', 'P', 'P', 'L', 'E', 'P'],
['A', 'G', 'C', 'A', 'A', 'I'],
['A', 'R', 'A', 'A', 'A', 'Z'],
['A', 'A', 'A', 'A', 'T', 'Z'],
['P', 'P', 'A', 'A', 'A', 'A'],
['A', 'E', 'P', 'R', 'A', 'Y']
];
if(this.width != this.height)
throw "height and width must be the same"
}
print(){
console.log(this)
}
}
puz = new Puzzle(6, 6);
now you can create a function that update the page and put values on elements:
you put all items on an 1D array
and then iterate items with 2 for cycle:
function updatePage(var x){
var elements = document.getElementsByClassName("item");
var k = 0;
for(var i = 0; i < puzzle.height; i++){
for(var j = 0; j < puzzle.width; j++){
elements[k].innerHTML = x.grid[i][j];
k++;
}
}
}
and finally you can call your function to view grid elements on the page:
updatePage(puzz);
I have the following list of divs and I'd like to be able to sort them using Javascript / JQuery.
<div class="item">
<div class="genre">Classical</div>
<div class="name">Alpha</div>
<div class="location">London</div>
</div>
<div class="item">
<div class="genre">Blues</div>
<div class="name">Bravo</div>
<div class="location">New York</div>
</div>
<div class="item">
<div class="genre">Pop</div>
<div class="name">Charlie</div>
<div class="location">Paris</div>
</div>
<div class="buttons">
Sort by Genre
Sort by Name
Sort by Location
</div>
I'd like to be able to sort the items by their Genre/Name/Location alphabetically.
Example: If Sort by Genre was clicked, it would sort the items in 0-9 A-Z by Genre.
If any of you have any tips it would greatly be appreciated.
Cheers :)
You have to make a little change to html like following:
<div id="container">
<div class="item">
<div class="genre">Classical</div>
<div class="name">Alpha</div>
<div class="location">London</div>
</div>
<div class="item">
<div class="genre">Blues</div>
<div class="name">Bravo</div>
<div class="location">New York</div>
</div>
<div class="item">
<div class="genre">Pop</div>
<div class="name">Charlie</div>
<div class="location">Paris</div>
</div>
</div>
<div class="buttons">
Sort by Genre
Sort by Name
Sort by Location
</div>
jQuery
function sorting(tag) {
var items = $('div.item').sort(function(a, b) {
var txt1 = $.trim($('div.' + tag, a).text()),
txt2 = $.trim($('div.' + tag, b).text());
if (txt1 > txt2) return 1;
else return -1;
});
return items;
}
$('.buttons a').on('click', function(e) {
e.preventDefault();
$('div#container').html(sorting(this.id));
});
Working Sample
Ok, this would be my pure JS solution.
First, we should wrap your <div>s into a larger container.
<div id = "wrapper">
<div id = "item">...</div>
<div id = "item">...</div>
<div id = "item">...</div>
</div>
Now, let's define a constant - which property do you want to sort it by? (this will probably be a function parameter later in your code).
var propName = "genre";
Let's get all the <div>s and put them in an array.
var items = document.getElementsByClassName("item");
var itemsArray = new Array();
Let us sort them lexicographically according to the text of the selected property.
for (var i = 0; i < items.length; i++)
itemsArray.push(items[i]);
itemsArray.sort(function(a, b) {
var aProp = a.getElementsByClassName(propName)[0].firstChild.nodeValue;
var bProp = b.getElementsByClassName(propName)[0] .firstChild.nodeValue;
if (aProp < bProp)
return -1;
else if (aProp > bProp)
return 1;
else
return 0;
});
Let us construct a document fragment consisting of the sorted <div>s.
var fragment = document.createDocumentFragment();
for (var i = 0; i < itemsArray.length; i++)
fragment.appendChild(itemsArray[i].clone());
Finally, let us clear the contents of the <div id = "wrapper"> and replace it with the document fragment.
document.getElementById('wrapper').innerHTML = '';
document.getElementById('wrapper').appendChild(fragment);
Also, note that document.getElementsByClassName does not work in IE<9, but I was now really lazy to cope with that issue.
A fiddle: http://jsfiddle.net/nNXr4/
Check this beast:
function sortByCreatedOnAsc(a,b){
return $(a).find('.created_on').text() > $(b).find('.created_on').text();
}
function sortByCreatedOnDesc(a,b){
return $(a).find('.created_on').text() < $(b).find('.created_on').text();
}
function reorderEl(el){
var container = $('#tasks');
container.html('');
el.each(function(){
$(this).appendTo(container);
});
}
$('#created_on').click(function(){
if($(this).hasClass("asc")){
reorderEl($('.task').sort(sortByCreatedOnDesc));
$(this).removeClass("asc");
$(this).addClass("desc");
} else {
reorderEl($('.task').sort(sortByCreatedOnAsc));
$(this).removeClass("desc");
$(this).addClass("asc");
}
return false;
});
jsfiddle: http://jsfiddle.net/jKJc3/116/