Calling a function via created HTML code - javascript

EDIT:
After some re-working to use another method (createElement) I've gotten my code to the point where it can properly call on elements, however it only uses the parameters of the last banner made at the end of the function. Here's the snippet of what I have to date.
function load() {
var staffB = ["Admin", "GM", "Dev", "FM", "Lore", "App", "Magic", "Event"];
var table = document.createElement("table");
for (var staffI = 0; staffI < staffB.length; staffI = staffI + 2) {
var row = document.createElement("tr");
var td = document.createElement("td");
var td2 = document.createElement("td");
var temp1 = staffB[staffI];
var temp2 = staffB[staffI + 1];
for (var i = 0; i < 10; i++) {
td.innerHTML = '<img src=banners/' + staffB[staffI] + '.png height="auto" width="100%">';
td.onclick = function() { select (temp1) }
td2.innerHTML = '<img src=banners/' + staffB[staffI + 1] + '.png height="auto" width="100%">';
td2.onclick = function() { select (temp2) }
}
row.appendChild(td);
row.appendChild(td2);
table.appendChild(row);
}
document.getElementById("staff").appendChild(table);
}
First time posting here, my apologies in advance for being a total nub.
So, to start off, I'm working on a page to assemble medieval-looking banners for a community that I'm part of, so in order to make it easy on myself to add/remove different banners in the future I made a modular HTML system using 'for'. When it's created it changes the names of the files it access to the names in an Array so that I only have to change the list and add a file. The HTML it creates is a table so that I can insert the images with two columns.
That table is then used for the selection menu as to which banner/curtain rod you'd be selecting. I have an ID attached to each <tr> based on the banner within (done during the creation of the HTML). Now I need to have it so that when they're clicked for selection, the sample image shown changes. Within the created HTML I created an onclick="select( Insert Banner Name Here )" in an effort to have the banner info transfer over to the next function, which is a switch.
I found out later that, from what I've seen, the function transfers a variable and not the word/data itself. I'm trying to think of a way I can code this so that, when called, the function knows what banner was clicked. When I tested the code it would always return [object HTMLTableCellElement].
In case I'm not making sense, this image may help. (Apologies for the bright colors, they're there so I can see the different divs easier).
The banners being selected are on the right, and the preview is on the left. The images on the right are within a table within a div (where the scroll bar is). That's where I'm trying to call my switch function from.
If anyone knows a way this is possible, or a better way of going about it I'd love for some help with it.

You might want to look into the document.createElement function.
http://www.w3schools.com/jsref/met_document_createelement.asp
With this you could do something like:
var staffB = ["http://i.stack.imgur.com/ziZF1.png", "http://i.stack.imgur.com/ziZF1.png", "http://i.stack.imgur.com/ziZF1.png"];
var table = document.createElement("table");
for (var staffI = 0; staffI < staffB.length; staffI = staffI + 2) {
var row = document.createElement("tr");
var td = document.createElement("td");
for (var i = 0; i < 10; i++) {
td.innerHTML = '<img src=' + staffB[staffI] + '.png height="auto" width="100%">';
}
td.onclick = function () {
//Whatever function you like
alert(1);
}
row.appendChild(td);
table.appendChild(row);
}
document.body.appendChild(table);
This way you have an object approach to your elements and thereby better control over your event listeners.
EDIT 1:
Example using anonymous functions to maintain the current loop state:
var staffB = ["http://www.faster-minis.com/site/speed-mini.jpg", "http://i.stack.imgur.com/ziZF1.png"];
var table = document.createElement("table");
for (var staffI = 0; staffI < staffB.length; staffI++) {
var row = document.createElement("tr");
for (var i = 0; i < 10; i++) {
var td = document.createElement("td");
td.innerHTML = '<img src=' + staffB[staffI] + ' height="auto" width="100%">';
//Anonymous scope to retain loop state
(function(a){
td.onclick = function () {
//Whatever function you like
//In here, "a" is the current "i"
alert(a);
alert(i);
}
})(i);
row.appendChild(td);
}
table.appendChild(row);
}
document.body.appendChild(table);

So, what I ended up doing was re-working it with divs instead. Doing that I was able to set the ID for each block, and from there send an onclick to a 'filter' function. The filter function then used the elements .id to extract which was which, and then send that info off to my switch function. Here's the code for those interested;
var staffB = ["Admin", "GM", "Dev", "FM", "Lore", "App", "Magic", "Event"];
for (var staffI = 0; staffI < staffB.length; staffI = staffI + 2) {
var co1 = document.createElement("div");
var co2 = document.createElement("div");
var wide = (282 / 2 - 10);
co1.setAttribute("id", staffB[staffI]);
co1.setAttribute("onclick", "filter(this)");
co1.style.float = "left";
co1.style.width = wide;
co1.innerHTML = '<img src=banners/' + staffB[staffI] + '.png height="auto" width="' + wide + '">';
co2.setAttribute("id", staffB[staffI + 1]);
co2.setAttribute("onclick", "filter(this)");
co2.style.float = "right";
co2.style.width = wide;
co2.innerHTML = '<img src=banners/' + staffB[staffI + 1] + '.png height="auto" width="' + wide + '">';
document.getElementById("staff").appendChild(co1);
document.getElementById("staff").appendChild(co2);
}
And the filter function;
function filter(ele) {
var id = ele.id;
select (id);
}
Hope this helps someone else if they find this post.

Related

HTML Table Row Creation

EDIT: With significant help from others, I was able to work up a solution.
I'm taking data from a Google Spreadsheet and then attempting to render it as an HTML table in a WebApp.
I'd like the data to show up like
<tr>
<td>
<td>
<td>
exactly how it looks in a spreadsheet, with each value in a separate cell.
Big picture, I'd like to be able to do different things to each <td>, so I want to make sure I structure the data in a usable way.
Code.GS
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function webAppTest() {
getTeamArray();
}
function getTeamArray() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName('Sheet1');
var range = sheet.getRange('A2:H1000');
var values = range.getValues();
//Logger.log(values);
var teamsArray = [];
for (var i = 0; i < values.length; ++i) {
var column = values[i];
var colA = column[0];
var colB = column[1];
var colC = column[2];
var colD = column[3];
var colE = column[4];
var colF = column[5];
var colG = column[6];
var colH = column[7];
if (colA != '') {
teamsArray.push(values[i][0]);
teamsArray.push(values[i][3]);
teamsArray.push(values[i][4]);
}
}
var array2 = [];
while(teamsArray.length) array2.push(teamsArray.splice(0,3));
var lengthDivName2 = array2.length;
var widthDivName2 = array2[0].length;
//Logger.log(teamsArray);
Logger.log(array2);
//return teamsArray;
return array2;
}
Index.HTML Function
function buildOptionsList(teamsArray) {
var div = document.getElementById('myList');
for (var i = 0; i < teamsArray.length; i++) {
var tr = document.createElement('tr');
var td = document.createElement('td');
var cLass = td.setAttribute('class','ui-state-default');
var iD = td.setAttribute('id',teamsArray[i]);
td.appendChild(document.createTextNode(teamsArray[i]));
div.appendChild(tr);
div.appendChild(td);
}
}
</script>
</head>
<body>
<div id="myList" class="connectedSortable">MY LIST</div>
</body>
</html>
ATTEMPT 1
ATTEMPT 2
I tried to change the array creation in code.gs which got all the correct data in the <tr> but didn't split into <td>s
I am not sure I understood the way you receive the data, but if teamsArray contain information about one line the solution would be something like this:
function buildOptionsList(teamsArray) {
var div = document.getElementById('myList');
var tr = document.createElement('tr');
for (var i = 0; i < teamsArray.length; i++) {
var td = document.createElement('td');
var cLass = td.setAttribute('class','ui-state-default');
var iD = td.setAttribute('id',teamsArray[i]);
td.appendChild(document.createTextNode(teamsArray[i]));
tr.appendChild(td);
}
div.appendChild(tr);
}
Use Array#map, Array#reduce, and Array#join to surround the elements of the inner array with the required HTML tags and then condense to a single string. Currently you have an implicit Array#toString call which creates a comma-separated string of the inner array's elements (the inner array is at teamData[i]), and thus you only have a single cell in your previous attempts' output.
This simple function assumes you aren't applying any column- or row-specific styles or attributes, so it can simply treat every <td> element equivalently. If you have symmetric styling to apply, you would want to process the headers/row variables with .map first (since you can then use the elements' indices) and then .join("") instead of just .join using the tag delimiters.
function getTableHTMLFrom(array, hasHeaders) {
if (!array || !array.length || !array[0].length)
return "";
const headerString = (hasHeaders ?
"<tr><th>" + array.shift().join("</th><th>") + "</th></tr>"
: "");
const tdTag = "<td class=\"ui-state-default\">";
const bodyString = array.reduce(function (s, row) {
s += "<tr>" + tdTag + row.join("</td>" + tdTag) + "</td></tr>";
return s;
}, "");
return "<table>" + headerString + bodyString + "</table>";
}
I found a solution (applied to Index.HTML) that worked based on THIS.
function buildOptionsList(array2) {
var table = document.createElement('table');
var tableBody = document.createElement('tbody');
array2.forEach(function(rowData) {
var row = document.createElement('tr');
rowData.forEach(function(cellData) {
var cell = document.createElement('td');
var cLass = td.setAttribute('class','ui-state-default');
cell.appendChild(document.createTextNode(cellData));
row.appendChild(cell);
});
tableBody.appendChild(row);
});
table.appendChild(tableBody);
document.body.appendChild(table);
}
buildOptionsList(array2);

Using JS loops to send unique vars from HTML buttons to function

Beginner here. I have a loop that creates 26 buttons with unique ID's and values. What I'm struggling with is figuring out the proper way to send the button's ID to a function so that I can store unique vars for each button independently without creating more than one function. I currently have an array with the 26 items I need for my buttons and the following loop:
function makeButtons() {
for (var i = 0; i < 26; i++) {
document.getElementById("whereButtonsGo").innerHTML += "<input type = 'button' value = '" + items[i] + "' id = 'button" + items[i] + "' onclick = doThing(button" + items[i] + ")'>";
}
}
I want the argument in the onclick function to be sent to a function such as:
function doThing(id) {
document.getElementById("'" + id.value + "'").style.color = "pink";
}
But so far I haven't been able to get this to work. Any help would be greatly appreciated!
Maybe this is what you are looking for:
makeButtons();
function makeButtons() {
for (var i = 0; i < 26; i++) {
document.getElementById("whereButtonsGo").innerHTML += "<input type = 'button' value = '" + i + "' onclick = doThing(this)>";
}
}
function doThing(currentButton) {
currentButton.style.color = "pink";
}
<div id="whereButtonsGo"/>
Try to keep the IDs as simple as possible
I recommend against using innerHTML for creating elements that you actually want to do something. Even if it works, your code will be amazingly unclear. Instead, write code that demonstrates that you're actually creating and adding elements:
var items = [1,2,3,4,5,6];
function makeButtons() {
var container = document.getElementById("whereButtonsGo");
for (var i = 0; i < items.length; i++) {
var button = document.createElement("button");
button.type = 'button';
button.value = items[i];
button.innerText = items[i];
button.id = 'button'+items[i];
button.onclick = doThing;
container.append(button)
}
}
function doThing() {
console.log('click of ' + this.id);
}
makeButtons();
Note that you don't need to pass the id in the function call for the event - the button that was clicked will be available as this.
Here is a fiddle.

Dynamically populate data into table using JavaScript

I am trying to populate table data dynamically in JavaScript. I managed to populate it but there is some problem with the styling, here is what I have achieved so far:
And my code to achieve the above:
function populateOverallOverview(result){
var tableData = new Array();
var table = document.getElementById("firstTabOverall");
for(var i = 0; i < result.length; i++){
tableData[i] = new Array('Category: ' + result[i].category + '\n Best selling month: ' + result[i].topMonthStr + '\n Amount: ' + result[i].topAmount.toFixed(2));
}
for(var i = 0; i < tableData.length; i++){
var newRow = table.insertRow(table.length);
for(var j = 0; j < tableData[i].length; j++){
var cell = newRow.insertCell(j);
cell.innerHTML = tableData[i][j];
}
}
}
My HTML code:
<div class="col-md-6">
<table id="firstTabOverall" class="table table-striped" style="font-size:13px">
</table>
</div>
What I wanted to achieve is for each row, there will be 3 different sub-rows for category, best selling month and amount. I am trying to split them into the next line using '\n' but it does not work.
Also, is there any way to bold the category, best selling month and amount wording in this case?
You do quite some unnecessary shifting-around of data. From results into a temp array, from the temp array into the table... why not from results straight into the table? Also, of course \n does not work. Line breaks mean nothing in HTML. You must add each cell individually.
The following looks a lot more straight-forward – and the Array#forEach() method rids you of the need for a separate loop counter, too:
function populateOverallOverview(result){
var table = document.getElementById("firstTabOverall");
// helper function
function addCell(tr, text) {
var td = tr.insertCell();
td.textContent = text;
return td;
}
// insert data
result.forEach(function (item) {
var row = table.insertRow();
addCell(row, 'Category: ' + item.category);
addCell(row, 'Best selling month: ' + item.topMonthStr);
addCell(row, 'Amount: ' + item.topAmount.toFixed(2));
});
}
Instead of repeating the category names in front of the values, write them into the header row. That's how a table is supposed to work anyway, right?
So, maybe this is better:
function populateOverallOverview(result){
var table = document.getElementById("firstTabOverall");
// helper function
function addCell(tr, text) {
var td = tr.insertCell();
td.textContent = text;
return td;
}
// create header
var thead = table.createTHead();
var headerRow = th.insertRow();
addCell(headerRow, 'Category');
addCell(headerRow, 'Best selling month');
addCell(headerRow, 'Amount');
// insert data
result.forEach(function (item) {
var row = table.insertRow();
addCell(row, item.category);
addCell(row, item.topMonthStr);
addCell(row, item.topAmount.toFixed(2));
});
}
Use CSS to style your table and table header. It might be easier to just write the header row into the static HTML source up-front.
If you positively must add bold text inline labels, you could use these document.createElement("b"), to get a <b> element, set its .textContent and then use .appendChild() of the respective container, in this case of the table cell.
You can add plain text the same way - just use document.createTextNode('...your text...') instead and append that.

How to speed up javascript table rendering?

I am building a large table on page load using javascript and I'm currently able to load the table portion in around 2 secs(on my machine of course). However, I was hoping it would be even faster. Any suggestions for improvement?
var fragment = document.createDocumentFragment();
var table=document.createElement('table')
table.className="table-bordered"
fragment.appendChild(table)
var body=document.createElement('tbody')
table.appendChild(body)
for (var i = 0; i < 200; i++) {
var row = document.createElement('tr');
body.appendChild(row);
for (var j = 0; j < 100; j++) {
var cell = document.createElement('td');
if(j!==0)
{cell.id="row"+i.toString()+"col"+(j-1).toString()
cell.className="myclass"
}
row.appendChild(cell);
}
}
Try moving this line: fragment.appendChild(table) to the very end of the code.
Otherwise, you are updating a table that is attached to the DOM and it may be trying to re-render things every time you add a new element.
It's likely the DOM rendering that's the bottleneck, so improving your code probably won't help much. However, I can suggest a few changes:
// declare all variables at head of code section--won't increase speed, but is good practice
var fragment = document.createDocumentFragment(),
table = document.createElement('table'),
body = document.createElement('tbody'),
i = 200,
j = 100,
row, cell;
table.className = "table-bordered";
table.appendChild(body);
// reverse while loop is faster than a traditional for loop
while(i--) {
row = document.createElement('tr');
body.appendChild(row);
while(j--) {
cell = document.createElement('td');
if(j !== 0) {
cell.id = ["row", i, "col", (j - 1)].join(""); // here we're joining an array instead of concatenating
// a string. Results in a minor improvement in speed.
cell.className = "myclass";
}
row.appendChild(cell);
}
j = 100;
}
// appending the table to the fragement after it's built means we don't modify the dom with each iteration of the below loops--this is
// probably the single largest improvement in speed
fragment.appendChild(table);
You can use
var inner_text = "<table><tbody>";
while(i--) {
var row = "";
row += "<tr> ";
while(j--) {
if(j !== 0) {
row +='<td ' + 'id="' + ["row", i, "col", (j - 1)].join("") +'"class="myClass"></td>';
}else{
row +='<td>' + '</td>';
}
}
row +=" </tr>";
inner_text +=row;
j = 100;
}
inner_text +="</tbody></table>";
That will reduce time to make new Element, append child.
Hope it helps you

Getting undefined string constraint error in Javascript

I want to pass a Javascript variable as a argument of a function called on onclick event of a checkbox, and the checkbox is created in innerHTML.
The code snippet is:
function populateValue(Result) {
var valueSet = new Array();
valueSet = Result.split("##");
for (i = 1; i < valueSet.length - 3; i++) {
var tr = document.createElement("tr");
var td = document.createElement("td");
tr.setAttribute("align", "left");
tr.className = "table_ce11";
td.setAttribute("align", "center");
var code = String(valueSet[i - 1]);
td.innerHTML = "<input type='checkbox' name='pCheckBox' value='111' id ='" + code + "' onClick=\"javascript:decide('" + code + "')\">";
tr.appendChild(td);
}
}
function decide(code) {
alert("here");
alert(document.getElementById(code).value);
if (document.getElementById(code).checked) alert("chked");
else alert("unchked");
}
while running this, neither am able to set the id nor to pass the argument of the function decide(). I get the error:
"undetermined string constraint".
But if I hardcode the values the function runs fine.
Any suggestions on this?
Just for starters
Split creates an array.
var valueSet = Result.split("##");
You need to test if there ARE at least 4 items in the array
if (valueSet.length <= 3) return
for (var i = 1; i < valueSet.length - 3; i++) {
no need to create a string when you string concatenate a string anyway
var code = valueSet[i - 1];
No need to use javascript: prefix and no need to pass the code when it is the same as the ID:
td.innerHTML = '<input type="checkbox" name="pCheckBox" value="111" id ="' + code + '" onClick="decide(this.id)">';
Also default align is left and you align center on the cell so get rid of
// tr.setAttribute("align", "left");
can you post more of the code and tell where things are going wrong exactly?

Categories