Appending to DOM after the loop - javascript

I would like to know how to append to the DOM just once after these nested loops.
Also, the variable letters is dynamic, so I would need to 'reset' my appended grid when a new string is passed to letters
let letters = "abcdefghijkl"
for (let i = 0; i < letters.length; i++) {
var musicRowID = `${letters.charAt(i)}01`;
$("#music-grid").append(`<div id="music-row-${musicRowID}" class="row no-gutters"></div>`);
for (let j = 1; j <= 12; j++) {
var columnID = letters.charAt(i) + (j < 10 ? "0" : "") + j;
$(`#music-row-${musicRowID}`).append(
`<div class="col-1"><button id="${columnID}" class="btn bar song">${columnID.toUpperCase()}</button></div>`
);
}
}
Thank you in advance!
EDIT
After the answer from T.J. Crowder I tried to incorporate my code to be able to populate my grid from the inputs, but when I unselect one of the inputs, that row isn't cleared.
let letters = 'abcdefghijkl';
let html = "";
$(".list-checkbox-item").change(function() {
let chosenLetters = $(this).val();
if ($(this).is(":checked")) {
arrayOfChoices.push(chosenLetters);
} else {
arrayOfChoices.splice($.inArray(chosenLetters, arrayOfChoices), 1);
}
letters = arrayOfChoices.sort().join(""); // Gives me a string with chosen letters ordered alphabetically
console.log(
`This is my string in var 'letters' ordered alphabetically (Need to clear grid after each instantiation or append after the loop): %c${letters}`,
"color: red; font-weight: bold; font-size: 16px"
);
for (let i = 0; i < letters.length; i++) {
var musicRowID = `${letters.charAt(i)}01`;
html += `<div id="music-row-${musicRowID}" class="row no-gutters">`; // *** No `</div>` yet
for (let j = 1; j <= 12; j++) {
var columnID = letters.charAt(i) + (j < 10 ? "0" : "") + j;
html += `<div class="col-1"><button id="${columnID}" class="btn bar song">${columnID.toUpperCase()}</button></div>`;
}
html += "</div>";
}
$("#music-grid").html(html);
});
What am I doing wrong?

Assuming #music-grid is empty before you run this code the first time, build up the HTML in a string and then use html() to replace the contents of #music-grid rather than appending to it:
let html = "";
for (let i = 0; i < letters.length; i++) {
var musicRowID = `${letters.charAt(i)}01`;
html += `<div id="music-row-${musicRowID}" class="row no-gutters">`; // *** No `</div>` yet
for (let j = 1; j <= 12; j++) {
var columnID = letters.charAt(i) + (j < 10 ? "0" : "") + j;
html +=
`<div class="col-1"><button id="${columnID}" class="btn bar song">${columnID.toUpperCase()}</button></div>`;
}
html += "</div>";
}
$("#music-grid").html(html);
You also see people building up the HTML in an array and using array.join("") at the end to get a single string, but with modern JavaScript engines it's really a wash either way...

Related

Nesting [innerHTML] in AngularJS

How can I 'nest' innerHTML bindings? Is it a sanitation problem?
I am using angular to create a website to play chess. I am dynamically creating a table and putting it into the component with: <div [innerHTML]="board | safeHTML"> where board with a string with the HTML for the table in and safeHTML is a pipe that bypasses sanitisation so the HTML isn't just read as a string. The code to generate the table is at the bottom of the post.
I would like to then be able to change the contents of each cell in the table.
Here is an example cell:
<td id="n${uniqueNumber}" class="board" [innerHTML]="boardValues.${uniqueNumber}">{{boardValues.${uniqueNumber}}}</td>
boardValues is an object that contains all of the cell data.
The table correctly displays when bound with [innerHTML] however the cells don't and [innerHTML] is displayed as an attribute (e.g. this image). Similarly {{boardValues.value}} shows up as plain text rather than the value.
How can I 'nest' innerHTML bindings? Is it a sanitation problem?
My html:
Running that doesn't work but it shows my main loops (the important one is generateBoard)
Here is a stack blitz project that sort of works but doesn't have formatting for some reason. Still shows my issue
generateBoard(n, playColour) {
var tblBuild = ""
var tblFooter = "<tr><td id=\"blank\"></td>"
for (var i = 0; i < 8; i++) {
tblFooter += `<th class="coordinates letters">${String.fromCharCode(97+i)}</th>`
}
tblFooter += "</tr>"
for (var i = 0; i <= n; i++) {
tblBuild += `<tr class="n${n-i+1}">`
tblBuild += `<th class="coordinates numbers">${n-i+1}</th>`
for (var j = 0; j <= n; j++) {
var idValue = `n${8*(n-i)+j}`
//want to assign the innerHTML to an object
tblBuild += `<td id="n${idValue}" class="board" [innerHTML]="boardValues.${idValue}">{{boardValues.${idValue}}}</td>`
}
tblBuild += ("</tr>")
}
var tbl = "<table id=\"board\" class= \"board " + playColour + "\"" + "<tbody>" + tblBuild + "</tbody>" + tblFooter + "</table>"
console.log(tbl)
return tbl
}
generateBoardValues(n) {
interface LooseObject {
[key: string]: any
}
var boardValues: LooseObject = {}
console.log("running generateBoardvalues")
console.log("n", n)
for (var i = 0; i <= n; i++) {
for (var j = 0; j <= n; j++) {
boardValues[`n${8*(n-i)+j}`] = `n${8*(n-i)+j}`
console.log("generating boardValues", boardValues[`n${8*(n-i)+j}`])
}
}
boardValues.n15 = "maually set"
console.log("n15", boardValues.n15)
console.log(Object.keys(boardValues).sort((a, b) => Number(a.slice(1)) - Number(b.slice(1)))) //sorted values
return boardValues
}
n = 7
boardValues = generateBoardValues(n)
board = generateBoard(n, "white")
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<p [innerHTML]="boardValues.n12"></p> <!--Works-->
<div [innerHTML]="board | safeHTML"> <!-- displays table but not desired cell contents-->
This approche is very expensive. I wouldn't use innerHTML in your case. You should handle this in your template file and use *ngFor.

How do I add 'x' number of <td> elements into a <tr> element in a for loop? [jQuery]

I am trying to make a square table dynamically through jQuery
My code so far is
$(document).ready(function() {
$('body').append('<table></table>');
initial();
});
var input = 16
function initial () {
for (i = 0; i < input; i++) {
$('table').append('<tr></tr>');
$('tr').append('<td></td>');
}
}
What I am trying to do is if I add 16 table row elements, then 16 table data elements will be added to each one, effectively creating a 16x16 grid
My current code only creates half of the table
I have to do this through jQuery
Sorry if it's simple, but I'm a bit daft
Thanks
You have to make two loops one after another:
$(document).ready(function() {
$('body').append('<table></table>');
initial();
});
var input = 16
function initial () {
for (i = 0; i < input; i++) {
$('table').append('<tr></tr>');
}
for (j = 0; j < input; j++) {
$('tr').append('<td>content</td>');
}
}
Btw its wrong way to create table, because you every time referring to DOM, which is expensive. You should first create string with table, then append it once to DOM:
var input = 16
function initial () {
var output = "<table>"
for (i = 0; i < input; i++) {
output += "<tr>";
for (j = 0; j < input; j++) {
output += "<td>content</td>";
}
output += "</tr>";
}
output += "</table>"
$('body').append(output);
}

Numeric text replace to alphabet using javascript

If you have any in a list item like 0123 then it will show abcd. again if it 5462 then will show fegc. my html code is below:
<div class="myList">
- 0123
- 5462
- 0542
</div>
Converted output will be
//////////
<div class="myList">
- abcd
- fegb
- afec
</div>
Is it possible to create using javascript?
Try something like this
var str = '0123';
var new_str = '';
for (var i = 0, len = str.length; i < len; i++) {
new_str += String.fromCharCode(97 + parseInt(str[i]));
}
alert(new_str)
The following will take the text from the element and change it accordingly while skipping non integer characters
$('.myList').text(convertNumbersToLetters($('.myList').text()))
function convertNumbersToLetters(numbers) {
new_str = '';
for (var i = 0; i < numbers.length; i++) {
new_str += isInt(numbers[i]) ? String.fromCharCode(97 + parseInt(numbers[i])) : numbers[i];
}
return new_str;
}
function isInt(n) {
return !isNaN(parseInt(n));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="myList">- 0123 - 5462 - 0542</div>
This is specific to your question.
alpha = ['a','b','c','d','e','f','g','h','i','j'];
function toNewString(input){
inputArray = input.split('');
for(i=0;i<inputArray.length; i++){
if(!isNaN(inputArray[i]))
inputArray[i] = alpha[inputArray[i]];
}
return inputArray.join('');
}
$('.myList').html(toNewString($('.myList').html()));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="myList">
- 0123
- 5462
- 0542
</div>
Do it like this (#DGS edited)
var str = ['0123', '456'];
var new_str = '';
for(var j=0; j < str.length; j++)
{
for (var i = 0; i < str[j].length; i++) {
new_str += String.fromCharCode(97 + parseInt(str[j][i]));
}
alert(new_str);
new_str = '';
}

I need to split every 3 div and append them to a div

I have a generic list
<div id="banner">
<div class="oneByOne_item top_offers">
<div class="top_offer_wrap">item1</div>
<div class="top_offer_wrap">item2</div>
<div class="top_offer_wrap">item3</div>
<div class="top_offer_wrap">item4</div>
<div class="top_offer_wrap">item5</div>
<div class="top_offer_wrap">item6</div>
</div>
</div>
But what I want to do is
<div id="banner">
<div class="oneByOne_item top_offers">
<div class="top_offer_wrap">item1</div>
<div class="top_offer_wrap">item2</div>
<div class="top_offer_wrap">item3</div>
</div>
<div class="oneByOne_item top_offers">
<div class="top_offer_wrap">item4</div>
<div class="top_offer_wrap">item5</div>
<div class="top_offer_wrap">item6</div>
</div>
</div>
I could use any advice as to the best way to deal with this situation.
If you remove the <div class="oneByOne_item top_offers"> in your HTML you can use the jQuery functions .slice() and .wrapAll() to add it again like so:
var div = $("#banner > div");
for(var i = 0; i < div.length; i+=3) {
div.slice(i, i+3).wrapAll("<div class='oneByOne_item top_offers'></div>");
}
Hope this helps.
Using pure javascript
function separate() {
var container = document.getElementById('banner');
var divElems = container.querySelectorAll(".top_offer_wrap");
var count = 0;
var newDiv = null;
for (var i = 3; i < divElems.length ; i++) {
if(count == 0) {
newDiv = document.createElement("div");
newDiv.className = 'oneByOne_item top_offers';
container.appendChild(newDiv);
}
var tempDiv = divElems[i];
tempDiv.parentNode.removeChild(tempDiv);
newDiv.appendChild(tempDiv);
count ++;
if(count == 3) {
count = 0;
}
}
}
Not tested though :)
It's not intelligent to do this with javascript. You should do this on the server-side.
If you really want to do it in javascript, you can use the following script:
var banner = document.getElementById('banner');
var children = banner.getElementsByClassName('oneByOne_item')[0].getElementsByTagName('div');
var output = "";
for( var i = 0; i < children.length; i += 3 ) {
var div = "<div class=\"oneByOne_item top_offers\">";
div += children[i].outerHTML;
if( i + 1 < children.length ) {
div += children[i+1].outerHTML;
}
if( i + 2 < children.length ) {
div += children[i+2].outerHTML;
}
div += "</div>";
output += div;
}
banner.innerHTML = output;
The code should be self-explenatory. I use getElementById, getElementsByClassName and getElementsByTagName to select the right element(s) to do the operations on.
Fiddle: http://jsfiddle.net/P95bQ/
you can use jQuery.
like this (already test):
var len = $('.top_offer_wrap').length,
length = len % 3 ? (len / 3) + 1 : len / 3,
html = '';
for(var i = 0; i < length; i++){
html += '<div class="oneByOne_item top_offers">';
for(var j = 1; j < 4 && i * 3 + j <= len; j++){
html += ' <div class="top_offer_wrap">item' + (i * 3 + j)+'</div>';
}
html += '<div>';
}
$('#banner').html(html);

A bit stuck with the "triangle" program in Javascript

I have a bit of an issue at the moment that I am hoping one of you can help me with. I have tried several things, and I just can't get it. I am trying to print a triangle of asterisks using JavaScript. The program is to ask the user for the amount of rows, and then the direction. I haven't even started with the direction yet because I can't get the rows to work. Odd thing is that I can get it to print out the triangle hard-coding the function call.
This is the JS file:
function myTriangle(){
var result = "";
var totalRows = document.getElementById('rows').value;
var direction = document.getElementById('UpOrDown').value;
for (var i = 1; i <= totalRows; i++){
document.writeln("count");
for (var j = 1; j <= 1; j++)
{
result += "*";
}
result += "<br/>";
}
return result;
}
var answer = myTriangle();
document.getElementById('myDiv').innerHTML = answer;
This is the HTML file:
<!DOCTYPE html>
<head>
<title>Lab 2</title>
<script src="scripts.js", "div.js"></script>
</head>
<body>
<form name="myForm">
<fieldset>
<legend>Input Fields</legend>
rows: <input type="text" id="rows" /><br>
direction: <input type="text" id="UpOrDown" /><br>
press: <input type="button" value="GO!" id="myButton"
onclick="myTriangle();"/>
</fieldset>
</form>
<div id="myDiv">
</div>
</body>
The output will be something like this:
*
**
***
****
*****
Generally there are four types of triangle -
1.)* 2.) *** 3.) * 4.) ***
** ** ** **
*** * *** *
Code for 1 -
var ast = [],
i, j = 4;
for (i = 0; i < j; i++) {
ast[i] = new Array(i + 2).join("*");
console.log(ast[i]);
}
Code for 2 -
var ast = [],
i, j = 4;
for (i = j-1; i >=0; i--) {
ast[i] = new Array(i + 2).join("*");
console.log(ast[i]);
}
Code for 3 -
var ast = [],
i, j = 4;
for (i = 0; i < j; i++) {
ast[i] = new Array(j - i).join(' ') + new Array(i + 2).join("*");
console.log(ast[i]);
}
Code for 4 -
var ast = [],
i, j = 4;
for (i = j-1; i >=0; i--) {
ast[i] = new Array(j - i).join(' ') + new Array(i + 2).join("*");
console.log(ast[i]);
}
To print asterisk in document rather than console -
document.getElementById('anyElement').innerHTML+=ast[i] + '<br />';
document.writeln will completely wipe the page unless it's called while the page is loading.
Therefore it will destroy myDiv, causing the getElementById to fail.
Furthermore, I'm not sure what you're trying to achieve with that <script> tag, but it looks like you need two of them.
EDIT: Oh, and this: for (var j = 1; j <= 1; j++) will only ever iterate once.
EDIT 2: Here's my implementation of a solution.
This isn't a valid script tag.
<script src="scripts.js", "div.js"></script>
You need to break it up into two tags:
<script src="scripts.js"></script>
<script src="div.js"></script>
This is my solution, it uses es2015 .replace() but there is a nice
polyfill for es5 as well here:
var output = document.getElementById('output');
function triangle (size) {
for (var i = 1; i <= size; i++) {
output.innerHTML += '*'.repeat(i) + '<br>';
}
}
triangle(2);
This is a solution in ES3/5
var output = document.getElementById('output');
function triangle(size) {
var allLines = '';
for (var i = 1; i <= size; i++) {
var oneLine = createLine(i);
allLines += oneLine;
}
return allLines;
}
function createLine(length) {
var aLine = '';
for (var j = 1; j <= length; j++) {
aLine += '*';
}
return aLine + "<br/>";
}
output.innerHTML += triangle(3);
<div id='output'></div>

Categories