How do I access DOM nodes from an array in javascript? - javascript

I am trying to build a drop-down menu that will show a row to the side of it when you hover over one of the cells with the mouse. I'm really new with using the DOM, and javascript as well.
The problem I'm running into is that the array I have created doesn't seem to access what I thought it should. Is it just my syntax, or do I need to approach this differently? Here is my code:
window.onload = function () {
var tableID = "strokerKitMenu";
var table = document.getElementById(tableID);
var tableRows = table.getElementsByTagName("tr");
var tableCell = [];
var counter = 0;
for (i = 0; i < tableRows.length; i++) {
tableCell[i] = new Array();
tableCell[i].push(tableRows[i].getElementsByTagName("td"));
}
for (i = 0; i < tableCell.length; i++) {
tableCell[0, i].style.display = "block"; //This doesn't compile
alert(tableCell[0, i].Text); //This comes back "undefined"
for (j = 1; j < tableCell[i].length; j++) //I haven't even tested this part yet
{
tableCell[i][j].onmouseover = function showCell() {
tableCell[i][j + 1].style.display = "block";
}
tableCell[i][j].onmouseout = function hideCell() {
this.style.display = "none";
}
} //end inner for loop
} //end outer for loop
}

tableCell[0, i].style.display="block"; //This doesn't compile
This syntax is invalid in JavaScript: you have specified two indices for tableCell but I guess you meant tableCell[0][i].style.display="block";
alert(tableCell[0, i].Text); //This comes back "undefined"
Once you fix the first error, you will want to change this to tableCell[0][i].textContent.

tableCell[i].push.apply(tableCell[i], tableRows[i].getElementsByTagName("td"));
You don't want to push the single array in. You want to push all the elements in. Otherwise you would have to access them as tableCell[i][0][j]

Related

createElement and loops [duplicate]

In JavaScript I am creating a grid (the type of grid you see in Photoshop) with HTML tables. The grid size is going to be variable, i.e., changeable by the user, so the size of each grid square must be calculated and divided by the number of pixels available to get an exact size grid.
I've done all this, but I have a problem adding in the necessary table elements to create the grid. My code is in full working order, except when I use the appendChild() function inside a for loop it only ever appends a single child, when it should be appending up to a couple of hundred.
My code:
grid.show = function(event)
{
var e = event;
if(grid.show_grid == false)
{
grid.show_grid = true;
parent.document.getElementById("grid_table").style.display = "block";
// Get grid (table) and create some elements.
grid.get_grid = parent.document.getElementById("grid_table");
grid.tr = parent.document.createElement("tr");
grid.td = parent.document.createElement("td");
// Clear the grid of all squares so we don't have to worry about subtracting anything.
grid.get_grid.innerHTML = "";
// Calculate the number of horizontal and vertical squares.
var horizontal = Math.ceil(grid.total_width / grid.size);
var vertical = Math.ceil(grid.total_height / grid.size);
// This was a nested loop, removed for demonstration.
// Attempting to add 10 "<tr><td></td></tr>" to the table.
for(var j = 0; j < 10; j++)
{
grid.tr.appendChild(grid.td);
}
//console.log(grid.tr);
// Add the elements to the table.
grid.get_grid.appendChild(grid.tr);
}
else
{
grid.show_grid = false;
parent.document.getElementById("grid_table").style.display = "none";
}
}
This only ever returns a single table row with single table data inside, like so:
<tr>
<td></td>
</tr>
I've already looked at this page and this page, and they sound promising but I just can't figure out how to make this work.
EDIT: Code now working, solution:
grid.show = function(event)
{
var e = event;
if(grid.show_grid == false)
{
grid.show_grid = true;
parent.document.getElementById("grid_table").style.display = "block";
grid.get_grid = parent.document.getElementById("grid_table");
grid.tr = null;
grid.td = null;
grid.get_grid.innerHTML = "";
var horizontal = Math.ceil(grid.total_width / grid.size);
var vertical = Math.ceil(grid.total_height / grid.size);
for(var i = 0; i < vertical; i++)
{
grid.tr = parent.document.createElement("tr");
for(var j = 0; j < horizontal; j++)
{
grid.td = parent.document.createElement("td");
grid.td.width = grid.size;
grid.td.height = grid.size;
grid.tr.appendChild(grid.td);
}
grid.get_grid.appendChild(grid.tr);
}
}
else
{
grid.show_grid = false;
parent.document.getElementById("grid_table").style.display = "none";
}
}
You are appending the same element over and over. You need to call document.createElement each time you wish to have a new element.
EDIT: If the element setup is really complicated and potentially includes children then you can also use Node.cloneNode
If you want to make one copy of the element, you will need to clone it. Use cloneNode()
So change
grid.tr.appendChild(grid.td);
to
grid.tr.appendChild(grid.td.cloneNode(true));
for(var j = 0; j < 10; j++)
{
grid.tr.appendChild(grid.td);
}
should be
for(var j = 0; j < 10; j++) {
var newTd = parent.document.createElement('td');
grid.tds.push(newTd); // if you need it, not sure why though
grid.tr.appendChild(newTd);
}

Unable to add all content to parent div inside a loop

The array gets console logged fine, but only the last person of the array is inserted in the HTML <div>.
Why or what is the failure?
document.getElementById("team").addEventListener("click", show)
function show(){
document.getElementById("fritz").style.display = "block";
document.getElementById("bill").style.display = "block";
document.getElementById("fran").style.display = "block";
for (i = 0; i < people.length; i++) {
var persoxn = people[i].printinfos()
document.getElementById('insert_text').innerHTML = persoxn
console.log(persoxn)
}
}
(https://imgur.com/IJbxvbR)
console
You are overriding (replacing) the <div> content in each iteration, therefore all of the elements except the last one get overwritten.
Maybe you meant to use .insertAdjacentHTML():
for (let i = 0; i < people.length; i++) {
var person = people[i].printinfos();
document.getElementById('insert_text').insertAdjacentHTML(person, "beforeend");
console.log(person);
}
Also don't forget to declare i inside the loop.

How to create a function to be re-used for later within another function

I got this code:
$(document).ready(function(){
$(".nextForm").on('click',(function(){
//check criteria
if(selectedSlots.length < 1 ||$("#positionAppliedFor").get(0).value.length < 1 ||$("#maxAmountOfHours").get(0).value.length < 1){
//error messages and array
var errorForSlots= "<h5>Select at least one availability slot</h5>";
var errorForPosition = "<h5>Enter the position you wish to apply for<h5>";
var errorForHours = "<h5>Enter the amount of hours you would like to work<h5>";
var errors = [];
//add errors to array
if(selectedSlots.length < 1){errors.push(errorForSlots)};
if($("#positionAppliedFor").get(0).value.length < 1){errors.push(errorForPosition)};
if($("#maxAmountOfHours").get(0).value.length < 1){errors.push(errorForHours)};
//create message
var div = "<div id=\"sectionError\">";
if($("#sectionError").length > 0){$("#sectionError").html('')};
$(div).appendTo($(this).get(0).parentNode);
for(var i = 0; i < errors.length; i++){
$(errors[i]).appendTo($("#sectionError"));
console.log(errors[i]);}
$("</div>").appendTo($(this).get(0).parentNode);
} else {
$("#applicationDetails").slideUp();
$("#personalDetails").slideDown();
if($("#sectionError").length > 0){$("#sectionError").remove()};
}
console.log("function finished");
}));
It all works perfectly, however, I am trying to figure out how to create a function for
//create message
var div = "<div id=\"sectionError\">";
if($("#sectionError").length > 0){$("#sectionError").html('')};
$(div).appendTo($(this).get(0).parentNode);
for(var i = 0; i < errors.length; i++){
$(errors[i]).appendTo($("#sectionError"));
console.log(errors[i]);}
$("</div>").appendTo($(this).get(0).parentNode);
I am planning to re-use this for few other sections on my form and rather than copy/paste I would like to get some help on making my code tidier.
I did try:
function myFunction(){
//message code here
}
$(document).ready(function(){
$(".nextForm").on('click',(function(){
//check criteria
...
//add errors
...
//call func
myFunction();
(I also tried this.myFunction();)
...
}));
});
However, that ended up in TypeError and I don't know where to begin...
I am also concerned about the "this" in my message code so I am also not sure how to address that in my new function...
Admitedly I am a newbie at this and I do not exactly understand all the ins and outs, hopefully you will be able to help.
Maybe there is a better way of doing this?
Let me know your thought either way!
Thanks.
I have created a small reusable framework same as how jQuery is doing behind the scene to expose reusable functions. I didn't tested the append function properly,I just explaining how you can create your own reusable plugin to reuse across the project.
You can change the parameters and method name that you want to expose based on your functionality.
Also I would suggest you to move this code to a javascript file as a plugin and drag after the jquery script.
(function (global, $) {
//you can pass the jQuery object in to this IIFE
var DisplayError = function (elementId) {
return new DisplayError.init(elementId);
}
DisplayError.prototype = {
appendError: function (errors) {
var div = "<div id=\"" + this.elementId + " \">";
if ($(this.elementId).length > 0) {
$(this.elementId).html('')
};
$(div).appendTo($(this.elementId).get(0).parentNode);
for (var i = 0; i < errors.length; i++) {
$(errors[i]).appendTo($(this.elementId));
}
$("</div>").appendTo($(this.elementId).get(0).parentNode);
}
};
DisplayError.init = function (elementId) {
var self = this;
self.elementId = elementId;
}
DisplayError.init.prototype = DisplayError.prototype;
global.DisplayError = global.DisplayError = DisplayError;
}(window, jQuery));
You can write the code for clear the html directly in init function to ensure the element is clearing while initialize the instance itself.
You can invoke the method like below ,
var displayError=DisplayError("#sectionError")
displayError.appendError(["errorId"])
or
DisplayError("#sectionError").appendError(["errorId"])
Hope this helps
New Function
function generateMessage(arg1) {
//create message for each section
console.log("generating message");
var div = "<div id=\"sectionError\">";
if ($("#sectionError").length > 0) {
$("#sectionError").html('')
}
;$(div).appendTo($(arg1).parent());
for (var i = 0; i < errors.length; i++) {
$(errors[i]).appendTo($("#sectionError"));
console.log(errors[i]);
}
$("</div>").appendTo($(arg1).parent());
}
Changed old function
$(document).ready(function() {
$("#adbutnext").on('click', (function() {
//check criteria
if (selectedSlots.length < 1 || $("#positionAppliedFor").get(0).value.length < 1 || $("#maxAmountOfHours").get(0).value.length < 1) {
//error messages and array
var errorForSlots = "<h5>Select at least one availability slot</h5>";
var errorForPosition = "<h5>Enter the position you wish to apply for<h5>";
var errorForHours = "<h5>Enter the amount of hours you would like to work<h5>";
errors = [];
//add errors to array
if (selectedSlots.length < 1) {
errors.push(errorForSlots)
}
;if ($("#positionAppliedFor").get(0).value.length < 1) {
errors.push(errorForPosition)
}
;if ($("#maxAmountOfHours").get(0).value.length < 1) {
errors.push(errorForHours)
}
;
generateMessage(this);
} else {
$("#applicationDetails").slideUp();
$("#personalDetails").slideDown();
if ($("#sectionError").length > 0) {
$("#sectionError").remove()
}
;
}
console.log("function finished");
}
));
});

JS: getElementByID wildcard

I have a table and a button.
If i click the button, all <tr> which have an id starting with "tr" (in the example the first 3) should be set to display = "none";
Here is a Fiddle
Has anyone a Idea how i get this to work?
Give all the elements that have id="tr_NNNN" a distinct class, e.g. class="tr tr_NNNN". Then use the following loop:
var hide_trs = document.getElementsByClassName('tr_NNNN');
for (var i = 0; i < hide_trs.length; i++) {
hide_trs[i].style.display = "none";
}
You can simply iterate through your tr elements using the IDs:
function doJS() {
for(var i = 1; i <= 3; i ++) {
document.getElementById("tr_" + i).style.display="none";
}
}
You can't supply a wildcard to gEBI, but you can use the attribute starts with selector in qSA:
document.querySelectorAll("[id^='tr_']")[0].style.display="none";
I agree with using classes instead of IDs for this, but this should satisfy your original question:
function doJS() {
var rows = document.getElementsByTagName("tr");
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
if(row.getAttribute("id") && /^tr/.test(row.getAttribute("id"))){
row.style.display = 'none';
}
}
}
http://jsfiddle.net/eHSwJ/14/
And while this isn't a jQuery question, I would point out that by leveraging jQuery, this can be reduced to:
$('tr[id^="tr"]').css('display', 'none');

Support for muliple table ids through javascript method

I am using the following method to read header names in a table and put in excel. Could anyone let me know how to modify this to support multiple tables with header info and data.
i.e. how to modify to pass table id. "headers" is the id for "th" tag in code.
function write_headers_to_excel()
{
str="";
var myTableHead = document.getElementById('headers');
var rowCount = myTableHead.rows.length;
var colCount = myTableHead.getElementsByTagName("tr")[0].getElementsByTagName("th").length;
var ExcelApp = new ActiveXObject("Excel.Application");
var ExcelSheet = new ActiveXObject("Excel.Sheet");
ExcelSheet.Application.Visible = true;
for(var i=0; i<rowCount; i++)
{
for(var j=0; j<colCount; j++)
{
str= myTableHead.getElementsByTagName("tr")[i].getElementsByTagName("th") [j].innerHTML;
ExcelSheet.ActiveSheet.Cells(i+1,j+1).Value = str;
}
}
Your question is a bit vague, so I'm guessing at what you want. Assuming your current function works as is, you can just take out the hard-coding of the table's ID and pass it in as a parameter:
function write_headers_to_excel(tableID) {
var myTableHead = document.getElementById(tableID);
// rest of your function as is
}
Then call it once for each table, though that will create a new ExcelSheet for each table.
If the idea is for all of the tables to be added to the same ExcelSheet you can pass an array of table IDs to the function something like the following. I've kept the basic structure of your function but moved the variable declarations out of the loops (since that what JavaScript does behind the scenes anyway), deleted your ExcellApp variable since it wasn't used, and moved the getElementsByTagName call out of the inner loop.
write_headers_to_excel(["headers1","headers3","headers7","etc"]);
function write_headers_to_excel(tableIDs) {
var myTableHead,
rowCount,
cols,
t,
i,
j,
rowOffset = 1,
ExcelSheet = new ActiveXObject("Excel.Sheet");
ExcelSheet.Application.Visible = true;
for (t=0; t < tableIDs.length; t++) {
myTableHead = document.getElementById(tableIDs[t]);
rowCount = myTableHead.rows.length;
for(i=0; i<rowCount; i++) {
cols = myTableHead.rows[i].getElementsByTagName("th");
for(j=0; j < cols.length; j++) {
ExcelSheet.ActiveSheet.Cells(i+rowOffset,j+1).Value = cols[j].innerHTML;
}
}
rowOffset += rowCount;
}
}
(No, I haven't tested it.)
You can get all tr elements by tag name
var rows = document.getElementsByTagName('tr');// get all rows of all tables
var table=0, TableRow=0;
for (i = 0; i < rows.length; i++) {
row = rows[i];
if (row.parentNode.tagName != 'THEAD' && row.parentNode.tagName != 'thead') {
table=table+1;
// do something here for headers
} else if (row.parentNode.tagName != 'TBODY' && row.parentNode.tagName != 'tbody')
{
TableRow=TableRow+1;
//do something here for rows
}
}

Categories

Resources