JavaScript createElement Line Causes Error - javascript

I'm writing a simple JavaScript program to examine every element in an HTML website and add a child node to every non-text node that labels the type of tag:
Here is my code:
window.onload = function() {
var body_elems = document.body.getElementsByTagName("*");
for (var i = 0; i < body_elems.length; i++) {
if (body_elems[i].nodeType != 3) {
var tag_name = body_elems[i].tagName;
var child = document.createElement("P");
var child_text = document.createTextNode(tag_name);
child.appendChild(child_text);
body_elems[i].appendChild(child);
body_elems[i].firstChild.className = "hoverNode";
}
}
}
For some reason the line var child = document.createElement("P") causes the page to never load; if I comment out that line then the page will load.
On the other hand, here is a slightly different version that actually works:
window.onload = function() {
var body_elems = document.body.getElementsByTagName("*");
for (var i = 0; i < body_elems.length; i++) {
if (body_elems[i].nodeType != 3) {
var tag_name = body_elems[i].tagName;
var child = document.createTextNode(tag_name);
body_elems[i].appendChild(child);
child.className="hoverNode";
}
}
}
But I can't figure out how to assign a class name to the new node in order to apply CSS, so if someone could tell me how to do that my problem would be solved.
I'm new to JS so any help would be much appreciated.

Related

Updating value in for loop / Reseting a for loop?

I'm working on my first school project so I don't have much experience in doing such web applications, that's why I decided to ask here.
How can I update the value in the for loop syntax or reset it entirely, so it iterates again, like I just reloaded it? I have another function that I decided not to show, simply because it would be useless to. What it does in the end is increments the taskCount.length by one. This part technically works but problem is, the function I'm going to show you now, once iterated, will always keep the default taskCount.length value, once the page is loaded, it never changes there. Is there any way I can update it?
Here's an example: The function above makes taskCount.length = '5' but when the page started it was taskCount.length = 4, and when I do alert(taskCount.length) from the console, I get 5. But the for loop doesn't want to change.
for (var i = 0; i < taskCount.length; i++) {
document.getElementsByClassName('task')[i].addEventListener('click', ((j) => {
return function() {
var shadow = document.createElement('div');
// Styling
var changingWindow = document.createElement('div');
// Styling
var changingTitle = document.createElement('p');
// Styling
var changingText = document.createElement('p');
// Styling
var changingTitleNode = document.createTextNode('Промяна');
var changingTextNode = document.createTextNode('Моля, изберете действие.');
var deleteTask = document.createElement('button');
var goUp = document.createElement('button');
var goDown = document.createElement('button');
var unchange = document.createElement('button');
// Styling
var deleteElementNode = document.createTextNode('Премахни задачата');
var goUpNode = document.createTextNode('Премести нагоре');
var goDownNode = document.createTextNode('Премести надолу');
var unchangeNode = document.createTextNode('Отказ');
var justBreak = document.createElement('br');
var justBreakAgain = document.createElement('br');
var justBreakOneMoreTime = document.createElement('br');
body.appendChild(shadow);
shadow.appendChild(changingWindow);
changingWindow.appendChild(changingTitle);
changingTitle.appendChild(changingTitleNode);
changingWindow.appendChild(changingText);
changingText.appendChild(changingTextNode);
changingWindow.appendChild(deleteTask);
deleteTask.appendChild(deleteElementNode);
deleteTask.onclick = function() {
document.getElementsByClassName('task')[j].parentNode.removeChild(document.getElementsByClassName('task')[j]);
shadow.parentNode.removeChild(shadow);
localStorage.setItem("listContent", document.getElementById('list').innerHTML);
}
changingWindow.appendChild(justBreak);
changingWindow.appendChild(goUp);
goUp.appendChild(goUpNode);
goUp.onclick = function() {
if (j !== 0) {
var saveThisTaskValue = document.getElementsByClassName('task')[j].innerHTML;
var savePreviousTaskValue = document.getElementsByClassName('task')[j - 1].innerHTML;
document.getElementsByClassName('task')[j].innerHTML = savePreviousTaskValue;
document.getElementsByClassName('task')[j - 1].innerHTML = saveThisTaskValue;
}
shadow.parentNode.removeChild(shadow);
localStorage.setItem("listContent", document.getElementById('list').innerHTML);
}
changingWindow.appendChild(justBreakAgain);
changingWindow.appendChild(goDown);
goDown.appendChild(goDownNode);
goDown.onclick = function() {
if (j !== document.getElementsByClassName('task').length - 1) {
var saveThisTaskValue = document.getElementsByClassName('task')[j].innerHTML;
var saveNextTaskValue = document.getElementsByClassName('task')[j + 1].innerHTML;
document.getElementsByClassName('task')[j].innerHTML = saveNextTaskValue;
document.getElementsByClassName('task')[j + 1].innerHTML = saveThisTaskValue;
}
shadow.parentNode.removeChild(shadow);
localStorage.setItem("listContent", document.getElementById('list').innerHTML);
}
changingWindow.appendChild(justBreakOneMoreTime);
changingWindow.appendChild(unchange);
unchange.appendChild(unchangeNode);
unchange.onclick = function() {
shadow.parentNode.removeChild(shadow);
}
}
})(i))
}
As a matter of the page reloading, you can always save the value as a cookie and reuse it again and again. You can update it whenever you want.
I don't fully understand you question, but maybe some recursion is what you need. Something along the lines of:
loop(5);
function loop(xTimes) {
for (var i = 0; i < xTimes; i++) {
if (newXTimes !== xTimes) {
loop(newXtimes);
break;
}
}
}
Maybe set newxTimes as a global variable that can be accessed inside loop.
In case someone "from the future" reads this question and it doesn't have any answers, I came up with the solution to reload the page everytime you change the value. Still, I'd like to do it without reloading.

Why can't I get my images to appear in table cells/nodes.. maybe I can get some closure?

I want to add a new image in each cell of the new table and give it the same source as the old table, and then make it clickable. Firstly, I did this:
function showData() {
if (localStorage.getItem(name) !== null) {
var showme = localStorage.getItem(name);
alert("I got the table");
var newTable = document.createElement('table');
newTable.innerHTML = showme;
newTable.id = "newTable";
newNumRows = newTable.getElementsByTagName('tr').length;
newNumCells = newTable.getElementsByTagName('td').length;
newNumCols = newNumCells / newNumRows;
alert(newNumRows);
alert(newNumCells);
alert(newNumCols);
var newImages = newTable.getElementsByTagName('img');
for (var i = 0; i < newImages.length; i += 1) {
var picSource = newImages[i]['src'];
console.log(picSource);
}
function addNewImage(newNumCols) {
var newImg = new Image();
newImg.src = picSource;
col.appendChild(newImg);
newImg.onclick = function() {
alert("WOW");
};
}
for (r = 0; r < newNumRows; r++) {
row = newTable.insertRow(-1);
for (c = 0; c < newNumCols; c++) {
col = row.insertCell(-1);
addNewImage(newNumCols);
}
}
var showIt = document.getElementById('holdTable');
showIt.appendChild(newTable);
}
}
This works to a certain extent, but, unfortunately, only the last image was displaying. So, I did a bit of looking around and I think it has to do with closure (apologies for any duplication), but it's a concept I am really struggling to understand. So then I tried this:
function showData() {
if (localStorage.getItem(name) !== null) {
hideTaskForm();
var showme = localStorage.getItem(name);
var oldTable = document.createElement('table');
oldTable.innerHTML = showme;
newTable = document.createElement('table');
newTable.id = "newTable";
var i, r, c, j;
newNumRows = oldTable.getElementsByTagName('tr').length;
newNumCells = oldTable.getElementsByTagName('td').length;
newNumCols = newNumCells / newNumRows;
var newTableCells = newTable.getElementsByTagName('td');
var getImages = oldTable.getElementsByTagName('img');
for (r = 0; r < newNumRows; r++) {
row = newTable.insertRow(-1);
for (c = 0; c < newNumCols; c++) {
makeNodes = row.insertCell(-1);
}
}
for (var j = 0; j < newTableCells.length; j++) {
var theNodeImage = document.createElement("img");
newTableCells[j].appendChild(theNodeImage);
alert(newTableCells[j].innerHTML); //This gives me img tags
}
for (i = 0; i < getImages.length; i += 1) {
var oldSource = getImages[i]['src']; //gets the src of the images from the saved table
console.log(oldSource);
//alert(oldSource);//successfully alerts the image paths
var newPic = new Image(); //creates a new image
(function(newPic, oldSource) {
newPic.src = oldSource;
alert(newPic.src); //gives the same image paths
newTable.getElementsByTagName('img').src = newPic.src; //This doesn't work - table is blank???
})(newPic, oldSource);
}
var showIt = document.getElementById('holdTable');
showIt.appendChild(newTable);
}
}
Now, this doesn't throw any errors. However, nor does it fill the table. It does give me the source and I think I have created the new image objects to attach to the img tags in the newTableCells, but the table is showing up blank. I don't know where I am going wrong. All help really welcome.
Note: Even as a hobbyist, even I know there are probably tons of more efficient ways to do this, but I purposely did it this way to try and help me understand the logic of each step I was taking.
In your code you have:
var newImages = newTable.getElementsByTagName('img');
for (var i = 0; i < newImages.length; i += 1) {
var picSource = newImages[i]['src'];
console.log(picSource);
}
At the end of this, picSource has the value of the last image's src attribute. Then there is:
function addNewImage(newNumCols) {
var newImg = new Image();
newImg.src = picSource;
col.appendChild(newImg);
newImg.onclick = function() {
alert("WOW");
};
}
A value is passed to newNumCols but not used in the function. The value of picSource comes from the outer execution context and is not changed, so it's still the last image src from the previous for loop.
for (r = 0; r < newNumRows; r++) {
row = newTable.insertRow(-1);
for (c = 0; c < newNumCols; c++) {
col = row.insertCell(-1);
addNewImage(newNumCols);
}
}
This loop just keeps calling addNewImage with a single parameter that isn't used in the function, so you get the same image over and over.
For the record, the addNewImage function does have a closure to picSource, but it also has a closure to all the variables of the outer execution contexts. This isn't the issue, though it perhaps masks the fact that you aren't setting a value for picSource on each call, so you get the left over value from the previous section of code.
You haven't provided any indication of the content of showme, so it's impossible to determine if this approach will work at all.
Note
Where you have:
var showme = localStorage.getItem(name);
alert("I got the table");
var newTable = document.createElement('table');
newTable.innerHTML = showme;
newTable.id = "newTable";
IE does not support setting the innerHTML property of table elements, though you can create an entire table as the innerHTML of some other element and set the innerHTML of a cell (tr, th). If you want to use this approach, consider:
var div = document.createElement('div');
div.innerHTML = '<table id="newTable">' + showme + '<\/table>';
var newTable = div.firstChild;

Google Apps Script: How to get this code run after UI is closed?

This may seem a very newbie question, but I'm stuck with it. I've got this code to show a check list in a UI and insert the paragraphs of one or more documents into another target document:
var fact_list = [ ["Kennedy Inauguration", "politics", "tZwnNdFNkNklYc3pVUzZINUV4eUtWVWFSVEf"], ["Pericles’ Funeral Oration", "politics", "sdgrewaNkNklYc3pVUzZINUV4eUtW345ufaZ"], ["The Pleasure of Books", "culture", "1234rFszdgrfYc3pVUzZINUV4eU43usacd"], ["I Am The First Accused (Nelson Mandela)", "law", "34rsgadOsidjSZIswjadi95uydnfklsdks"] ];
function showList() {
var mydoc = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication();
var panel = app.createVerticalPanel().setId('panel');
// Store the number of items in the array (fact_list)
panel.add(app.createHidden('checkbox_total', fact_list.length));
// add 1 checkbox + 1 hidden field per item
for(var i = 0; i < fact_list.length; i++){
var checkbox = app.createCheckBox().setName('checkbox_isChecked_'+i).setText(fact_list[i][0]);
var hidden = app.createHidden('checkbox_value_'+i, fact_list[i]);
panel.add(checkbox).add(hidden);
}
var handler = app.createServerHandler('submit').addCallbackElement(panel);
panel.add(app.createButton('Submit', handler));
app.add(panel);
mydoc.show(app);
}
function submit(e){
var numberOfItems = e.parameter.checkbox_total;
var itemsSelected = [];
// for each item, if it is checked / selected, add it to itemsSelected
for(var i = 0; i < numberOfItems; i++){
if(e.parameter['checkbox_isChecked_'+i] == 'true'){
itemsSelected.push(e.parameter['checkbox_value_'+i]);
}
}
var app = UiApp.getActiveApplication();
ScriptProperties.setProperties({'theses': itemsSelected}, true);
app.close();
return app;
}
function importTheses(targetDocId, thesesId, thesesType) { // adapted from Serge insas
var targetDoc = DocumentApp.openById(targetDocId);
var targetDocParagraphs = targetDoc.getParagraphs();
var targetDocElements = targetDocParagraphs.getNumChildren();
var thesesDoc = DocumentApp.openById(thesesId);
var thesesParagraphs = thesesDoc.getParagraphs();
var thesesElements = thesesDoc.getNumChildren();
var eltargetDoc=[];
var elTheses=[];
for( var j = 0; j < targetDocElements; ++j ) {
var targetDocElement = targetDoc.getChild(j);
// Logger.log(j + " : " + type);// to see targetDoc's content
eltargetDoc[j]=targetDocElement.getText();
if(el[j]== thesesType){
for( var k = 0; k < thesesParagraphs-1; ++k ) {
var thesesElement = thesesDoc.getChild(k);
elTheses[k] = thesesDoc.getText();
targetDoc.insertParagraph(j, elTheses[k]);
}
}
}
}
But when I call these functions inside my main function, I got a red message (in my language): service not available: Docs and, after the UI from showList() is closed, nothing more happens with my code (but I wanted the main functions continues to run). I call these functions this way:
if (theses == 1){
showList();
var thesesArrays = ScriptProperties.getProperty('theses');
for (var i = 0; i < thesesArrays.lenght(); i++){
var thesesId = ScriptProperties.getProperty('theses')[i][2];
var thesesType = ScriptProperties.getProperty('theses')[i][1];
importTheses(target, thesesId, thesesType);
}
}
showURL(docName, link); // Shows document name and link in UI
So, how can I fix that? How can I get the code run until the line showURL(docName, link);?
showList();
This function creates only Ui.
You are setting the script properties only in the Server Handler which executes on the click of submit button. Since then:
ScriptProperties.getProperty('theses');
will hold nothing. So you need to call these lines:
var thesesArrays = ScriptProperties.getProperty('theses');
for (var i = 0; i < thesesArrays.lenght(); i++){
var thesesId = ScriptProperties.getProperty('theses')[i][2];
var thesesType = ScriptProperties.getProperty('theses')[i][1];
importTheses(target, thesesId, thesesType);
}
Inside server handler or put them inside a method and call the method from the server Handler.

How can I change the content of the "h1" tag of an html page using javascript?

I need to change the content of all "h1" tags in my html file when the page load using javascript.
So I write the following code
window.onload = function () {
var h1html = document.createElement("h1");
var h1htmltext = document.createTextNode("header 1");
h1html.appendChild(h1htmltext);
document.getElementsByTagName("h1").appendChild(h1html);
};
If you're sure you only have one h1 tag you could simply do
window.onload = function () {
document.getElementsByTagName("h1")[0].innerHTML = "header 1";
}
if multiple h1 tags are present you could do
window.onload = function () {
var h1Elems = document.getElementsByTagName("h1");
var pos;
for (pos in h1Elems) {
h1Elems[pos].innerHTML = "header 1";
}
}
Use this:
for(var i = 0, elems = document.getElementsByTagName('h1'); i < elems.length; i++) {
elems[i].innerHTML = "new";
}
fiddle
You need to change the innerHTML of each elements, as such
function changeall(){
var headers=document.getElementsByTagName("h1");
var newheadertext="hello";
for(var i in headers){
headers[i].innerHTML=newheadertext;
}
}
getElementsByTagName returns a node list; you need to loop through it.
var headers = document.getElementsByTagName("h1");
for(var i = 0; i < headers.length; i++) {
var header = headers[i];
var text = document.createTextNode("header 1");
while(header.childNodes.length) {
header.removeChild(header.firstChild);
}
header.appendChild(text);
}
I made a few assumptions there:
You don’t actually want to nest headers
You want to replace the content
You want an old-standards-compliant way
If you don’t need support for old browsers, just use textContent:
var headers = document.getElementsByTagName("h1");
for(var i = 0; i < headers.length; i++) {
headers[i].textContent = "header 1";
}

How do I access DOM nodes from an array in 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]

Categories

Resources