I have two buttons, each button adds an array to the array orderArray. This works fine and the array is displayed as a html table. When the table is output a button is also created. This buttons purpose is to remove the array associated with it, and hence remove a line from the table.
This works fine, but after removing part of the array with .splice it is not possible to then add more to the array, it just throws "cannot read property length".
You can see in the console that the array is spliced and that the length value is correct but the error still persists. I am clearly not getting something here, as I thought that as the loop calls myArray.length it would get the right length every time.
Here is the js:
var orderArray = [];
var orderNumber = 0;
var theOrder = [];
var total = 0;
function orderUpdate(item,price){
theOrder = [item, price];
orderArray[orderNumber] = theOrder;
orderNumber++;
}
function makeTable(myArray) {
var result = "<table border=2 id=orderTable>";
console.log(myArray.length);
for(var i = 0; i < myArray.length; i++) {
result += "<tr id='row" + i + "'>";
for(var j = 0; j < myArray[i].length; j++){
result += "<td>" + myArray[i][j] + "</td>";
}
result += "<td><button onclick='removeLine(" + i + ")'>Remove</button></td></tr>";
}
result += "</table>";
console.log(myArray);
return result;
}
$( "#LongB" ).click(function() {
orderUpdate("Long Black", 2.50);
$("#ordered").html(makeTable(orderArray));
});
$( "#FlatW" ).click(function() {
orderUpdate("Flat White", 3.50);
$("#ordered").html(makeTable(orderArray));
});
function removeLine(arrayIndex){
orderArray.splice(arrayIndex, 1);
console.log(orderArray);
$("#ordered").html(makeTable(orderArray));
}
and the html:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JSPOS</title>
<script src="http://code.jquery.com/jquery-2.1.4.js"></script>
</head>
<body>
<button id="LongB">Long Black</button>
<button id="FlatW">Flat White</button>
<h3>Ordered:</h3>
<div id="ordered"></div>
<script src="js/stuff.js"></script>
</body>
</html>
and here it is as a fiddle.
This is because you are increasing the orderNumber when you add new item but when you remove the item you forgot to decrease the orderNumber so you got the error because index doesn't exists in array:-
function removeLine(arrayIndex){
orderArray.splice(arrayIndex, 1);
console.log(orderArray);
orderNumber--; //add this line
$("#ordered").html(makeTable(orderArray));
}
Demo
Try substituting orderArray.push(theOrder); for orderArray[orderNumber] = theOrder;
function orderUpdate(item,price){
theOrder = [item, price];
orderArray.push(theOrder);
// orderNumber++;
}
jsfiddle https://jsfiddle.net/purnrntr/2/
Related
I want to print html code in Javascript code.
I want to open and close the bottom line of five li tags. How can I do this with a for loop
jQuery(document).ready(function () {
InsertLi();
});
function InsertLi(){
var count = 5;
for (var i = 0; i < count; i++) {
var codeBlock = ' <li>' + i + '</li>';
$(".bildirimMetin").html(codeBlock);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="bildirimMetin">
</ul>
You need to use append function instead. html function every time overrides your html content with the new content and you get only the last one. Also create your string with 5 li-s and then call the append at the end to work with DOM one time and have more performance.
function InsertLi() {
var count = 5;
var codeBlock = '';
for (var i = 0; i < count; i++) {
codeBlock += ' <li>' + i + '</li>';
}
$(".bildirimMetin").append(codeBlock);
}
jQuery(document).ready(function () {
InsertLi();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="bildirimMetin"></ul>
If you have only one item with bildirimMetin class, it will be better to use id instead of class.
Well, another solution, close to your code, with html, store all strings in your variable via += then you must define your variable before for loop also move your html after it. Your current code not working because it just store last string not all.
InsertLi();
function InsertLi() {
var count = 5;
var codeBlock = '';
for (var i = 0; i < count; i++) {
codeBlock += '<li>' + i + '</li>';
}
$(".bildirimMetin").html(codeBlock);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="bildirimMetin">
</ul>
you had a couple issues. One was overwriting the inner HTML instead of appending. The other was a syntax issue.
function InsertLi(){
var count = 5;
for (var i = 0; i < count; i++) {
var codeBlock = ' <li>' + i + '</li>';
$(".bildirimMetin").append(codeBlock);
}
}
jQuery(document).ready(function () {
InsertLi();
}
);
The idea is to build a function that takes an input and uses that to build a grid. I'm trying to establish the grid functionality first, and I'm having a peculiar error. I searched for a few hours, but the answers all tell me that a simple "append" should be working.
The specific error that I am getting:
When I load up the webpage, it is only adding one table row to the tbody, and only one table data to that table row. The idea is instead to create a grid of 16 x 16, with 16 rows and 16 data. Console logs show that the loops are all working correctly.
The html is just a basic file that imports the javascript correctly (All tested) with a simple:
div class="container" /div
Code:
$(document).ready(function(){
$(".container").html("");
/*this function makes a table of size numRow and
num data. it then gives each data element
*/
//blank rows to insert
var blankResults = $("<table>");
var result = blankResults;
var row = $("<tr/>");
var data = $("<td/>");
function makeTable(num)
{
result = blankResults;
//create num rows
for (var i = 0; i < num; i++)
{
//for each row
//add data num times
for (var j = 0; j < num; j++)
{
console.log(j);
row.append(data);
}
//append row
console.log(i);
result.append(row);
}
}
//starting area
makeTable(16);
$(".container").append(result);
//Start with 16 by 16 of square divs -
//put inside a container div
});
Try this code.
$(document).ready(function(){
$(".container").html("");
/*this function makes a table of size numRow and
num data. it then gives each data element
*/
function makeTable(num)
{
var output = '<table>';
//create num rows
for (var i = 0; i < num; i++)
{
//for each row
output+= '<tr>'
for (var j = 0; j < num; j++)
{
output += '<td></td>';
}
output += '</tr>';
}
output += '</table>';
return output;
}
//starting area
var result = makeTable(16);
$(".container").append(result);
//Start with 16 by 16 of square divs -
//put inside a container div
});
You are appending to the same variables all the time...row and 'data`. you should not do that.
As you can see from the code below, you need to create the var row = $("<tr>"); on each loop, to reference it when you append the <td> (table cell) to that newly created row.
Modifed to use only one loop:
$(document).ready(function(){
function makeTable(num) {
var table = $("<table>"), row;
for (var i = 0; i < num; i++){
row = $("<tr>");
table.append(row);
row.append(Array(num + 1).join("<td></td>"));
}
return table;
}
$(".container").html(makeTable(16));
});
DEMO PLAYGROUND
Of course, this is not a good way generating a table. running jQuery function on each loop is slow and bad practice. You should generate a big string which will represent your DOM structure and then append that string where needed and jQuery will make a DOM node out of it.
I made up my own html for this but it should be as simple as using two nested for loops grabbing values the size input. Here's what I came up with:
$("#tableMaker").click(function () {
$('.container').html("");
$('.container').append("<table></table>");
for (var i = 0; i < $('#size').val(); i++) {
$('table').append("<tr></tr>");
for (var j = 0; j < $('#size').val(); j++) {
$('tr:last').append("<td>Column " + (j+1) + ", Row " + (i+1) + "</td>");
}
}
})
td {
border: black solid 1px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="number" id="size" placeholder="Size" />
<button id="tableMaker" type="button">Generate Table</button>
<br />
<div class="container">
<div />
I can't figure out why my page will not work. It just gives me a white screen when I try to load it. Is there a code I am missing? I don't know if my spaces matter either. Here is my code:
<!DOCTYPE html>
<html>
<head><body>
<title>Initializing an Array</title>
<style type="text/css">
table {width:10em}
th {text-align:left}
</style>
<script language="JavaScript">
<!--
{//create (declare) two new arrays
var n1=new Array(5); //allocate five-element Array
var n2=new Array (); //allocate empty Array
//assign values to each element of Array n1
for ( var i = 0; i <n1.length; ++i )
n1[ i ] = i;
//create and initialize five elements in Array n2
for ( i=0; i <5; ++i )
n2[ i ] = i;
outputArray("Array n1:",n1);
outputArray("Array n2:",n2);
//output the heading followed by a two-column table
//containing subscripts and elements of "theArray"
function outputArray (heading,theArray)}
{
document.writeln("<h2>"+heading+"</h2>");
document.writeln("table border=\"1\"");
document.writeln("<thead><th>Subscripts</th>"+"<th>Value</th></thead> <tbody>");
//output the subscript and value of each array element
for ( var i = 0; i <theArray.length; i++ )
document.writeln("<tr><td>+i+"</td><td>"+theArray[i]+"</td></tr>");
document.writeln("/tbody></table>");
} //end function outputArray
//-->
</script>
</head></body>
</html>
Please help! Thanks.
You have broken HTML and invalid Javascript.
<script language="JavaScript">
For your DOCTYPE of html, there is no need to specify any attributes to a <script> tag except src, and that is only needed if you are loading an external script file. And there is no attribute language. You likely meant type="text/javascript" but that is the default and therefore redundant.
<!--
You can't have HTML comments inside a <script> block. You are telling the browser that what is inside the <script> block is Javascript, then you putting invalid javascript. There will likely be errors displayed in the console.
Your example, tidied up, would look something like this:
<script>
// create (declare) two new arrays
var n1 = new Array(5); //allocate five-element Array
var n2 = new Array(); //allocate empty Array
// assign values to each element of Array n1
for (var i = 0; i < n1.length; ++i) {
n1[ i ] = i;
}
// create and initialize five elements in Array n2
for (i=0; i < 5; ++i) {
n2[ i ] = i;
}
outputArray("Array n1:",n1);
outputArray("Array n2:",n2);
// output the heading followed by a two-column table
// containing subscripts and elements of "theArray"
function outputArray (heading, theArray) {
var html = '<h2>' + heading + '</h2>';
html += '<table border="1">';
html += '<thead><th>Subscripts</th><th>Value</th></thead>';
html += '<tbody>';
// output the subscript and value of each array element
for (var i = 0; i < theArray.length; i++) {
html += '<tr><td>' + i + '</td><td>' + theArray[i] + '</td></tr>';
}
html += '</tbody></table>';
var div = document.createElement('div');
div.innerHTML = html;
document.body.appendChild(div);
}
</script>
You forgot quote " and on the next line < in </tbody> in last for loop.
document.writeln("<tr><td>"+i+"</td><td>"+theArray[i]+"</td></tr>");
^
document.writeln("</tbody></table>");
^
Of course nothing gets displayed, the base HTML layout is completely wrong.
You wrote :
<head>
<body>
(all the stuff)
</head>
</body>
It should be :
<head>
(scripts.....)
</head>
<body>
(HTML....)
</body>
I have a Google Apps Script web app that contains an HTML form with a couple of drop-down lists. When the user submits their choices, a function looks them up in a Google spreadsheet and returns corresponding values in an array. This array could have any length, and I am having trouble getting it to display as an HTML list without having a set list length.
I have this GAS script:
function doGet() {
return HtmlService.createHtmlOutputFromFile('index')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function discern(formObject) {
var stage = formObject.stage;
var service = formObject.service;
var ss = SpreadsheetApp.openById(ID);
var dataSheet = ss.getSheetByName('Sheet1');
var dataRange = dataSheet.getDataRange();
var data = dataRange.getValues();
var array = [];
for(var i = 0; i < data.length; i++) {
if(data[i][1].indexOf(stage) > -1) {
if(data[i][2].indexOf(service) > -1) {
array.push(data[i][0]);
}
}
}
return array;
}
And this HTML:
<script>
function printList(array) {
var div = document.getElementById('results');
var list = HtmlService.createHtmlOutput('<ul>');
for (var i = 0; i < array.length; i++) {
list.append('<li>' + array[i] + '</li>');
}
list.append('</ul>');
}
</script>
<form id="myForm">
<h3>Farming Stage</h3><br>
Select your farming stage.<br>
<select name="stage">
<option etc etc etc
</select><br>
<h3>Services</h3><br>
Select the service for which you are looking<br>
<select name="service">
<option value= etc etc etc</option>
</select><br>
<br><input type="button" value="Discern"
onclick="google.script.run
.withSuccessHandler(printList)
.discern(this.parentNode)"/>
</form>
<ul id="results"></ul>
(I've replaced some sections with "etc" to save space. The form itself is not the issue.)
Anyway, right now the app returns nothing. Earlier I had the printList function as:
function printList(array) {
var div = document.getElementById('output');
div.innerHTML =
'<ul><li>' + array[0] +
'</li><li>' + array[1] +
'</li><li>' + array[2] +
'</li><li>' + array[3] +
'</li><li>' + array[4] +
'</li></ul>';
}
This version worked, but it was limited to 5 list slots, and the unused slots showed up as "undefined," which was annoying.
Does anyone have any suggestions? Was I close with the 'for' loop in my printList function? Is there another simple way to go about this? I would really appreciate any help or feedback.
Thanks,
Bill
You get the div results do you mean to append the list to the html?
<script>
function printList(array) {
var div = document.getElementById('results');
var list = HtmlService.createHtmlOutput('<ul>');
for (var i = 0; i < array.length; i++) {
list.append('<li>' + array[i] + '</li>');
}
list.append('</ul>');
// ?
div.innerHTML = list.getContent();
}
</script>
edit Also I think you need to getContents of the html Object.
You could not use the HTMLService. Personally I never got it to work the way I wanted it to when I used it. (a couple years ago).
Why not use your loop and just append the string to the div like this.
<script>
function printList(array) {
var div = document.getElementById('results');
var list = '<ul>');
for (var i = 0; i < array.length; i++) {
list += '<li>' + array[i] + '</li>';
}
list += '</ul>';
div.innerHTML = list;
}
</script>
For whatever reason, it worked when I did it this way:
...<br><input type="button" value="Discern"
onclick="google.script.run
.withSuccessHandler(showThings)
.discern(this.parentNode)"/>
</form>
<p>List of services:</p>
<ul id="things">
<li>Waiting...</li>
</ul>
<script
src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script>
function showThings(array) {
var list = $('#things');
list.empty();
for (var i = 0; i < array.length; i++) {
list.append('<li>' + array[i] + '</li>');
}
}
</script>
What I'm trying to accomplish with this code is to output the array alphabet as a series of list items into an existing unordered list in the actual markup. I've got the array into list items, but I can't figure out how to tell it to append itself to an existing unordered list <ul id="itemList"></ul>.
var itemsExist = true;
var indexNum = 0;
var unorderedList = document.getElementById('itemList');
var alphabet= new Array("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");
function write_letters(){
for (i = 0; i < alphabet.length; i++ ) {
document.write('<li>' + alphabet[indexNum++] + '</li>');
}
}
if (itemsExist){
write_letters();
} else {
document.write("error!");
}
Don't use document.write to do it. You should act like this:
function write_letters(){
var letters = "";
for (var i = 0; i < alphabet.length; i++ ) {
//Also I don't understand the purpose of the indexNum variable.
//letters += "<li>" + alphabet[indexNum++] + "</li>";
letters += "<li>" + alphabet[i] + "</li>";
}
document.getElementById("itemList").innerHTML = letters;
}
More proper way is to use DOM (in case you want full control of what's coming on):
function write_letters(){
var items = document.getElementById("itemList");
for (var i = 0; i < alphabet.length; i++ ) {
var item = document.createElement("li");
item.innerHTML = alphabet[i];
items.appendChild(item);
}
}
You can use a combination of createElement() and appendChild() to add new HTML elements within another HTML element. The code below should work for you:
<html>
<head>
<title>Script Test</title>
</head>
<body>
<ul id="itemList"></ul>
</body>
<script>
var itemsExist = true;
var indexNum = 0;
var unorderedList = document.getElementById('itemList');
var alphabet= new Array("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");
var myElement;
function write_letters(){
for (i = 0; i < alphabet.length; i++ ) {
// Create the <LI> element
myElement = document.createElement("LI");
// Add the letter between the <LI> tags
myElement.innerHTML = alphabet[indexNum++];
// Append the <LI> to the bottom of the <UL> element
unorderedList.appendChild(myElement);
}
}
if (itemsExist){
write_letters();
} else {
document.write("error!");
}
</script>
</html>
Note how the script exists below the body tag. This is important if you want your script to work the way you wrote it. Otherwise document.getElementById('itemList') will not find the 'itemList' ID.
Try to reduce the actions on the DOM as much as possible. Every appendChild on unorderedList forces the browser to re-render the complete page. Use documentFragement for that sort of action.
var frag = document.createDocumentFragment();
for (var i = alphabet.length; i--; ) {
var li = document.createElement("li");
li.appendChild(document.createTextNode(alphabet[indexNum++]));
frag.appendChild(li);
}
unorderedList.appendChild(frag);
So there will be only one DOM action which forces a complete redraw instead of alphabet.length redraws