Looping error in Javascript with eventHandler - javascript

I have the following Javascript code within and HTML page. Its function is to display elements on the form based on the user pressing a + button and if the element is not needed then it removes it via the user pressing the - button. Currently its throwing an error "TypeError: docs[n]" is undefined after the following sequence of events:
Select button to add elements
Remove elements not needed
Add elements back (Error Thrown)
Any help would be most appreciated
`<script language="JavaScript">`
var idx = 0;
var d;
//Make getElementsByClassName work for all of IE revs
if (!document.getElementsByClassName) {
document.getElementsByClassName = function (cn) {
var rx = new RegExp("(?:^|\\s)" + cn+ "(?:$|\\s)");
var allT = document.getElementsByTagName("*"), allCN = [],ac="", i = 0, a;
while (a = allT[i=i+1]) {
ac=a.className;
if ( ac && ac.indexOf(cn) !==-1) {
if(ac===cn){ allCN[allCN.length] = a; continue; }
rx.test(ac) ? (allCN[allCN.length] = a) : 0;
}
}
return allCN;
}
}
function add_fields(e) {
// for some reason, adding the new fields wipes out existing values, so save and restore
var docs = document.getElementsByClassName("doc");
var revs = document.getElementsByClassName("rev");
++idx;
/* console.log("test " + idx); */
var saveDocs = new Array(idx);
var saveRevs = new Array(idx);
for (n=0; n < idx; n++) {
saveDocs[n] = docs[n].value; **//Error is thrown here**
saveRevs[n] = revs[n].value;
}
node = document.getElementById("content");
theNewRow = document.createElement("tr");
theNewCell = theNewRow.insertCell(0);
theNewCell.innerHTML = "Approver Name";
theNewCell.setAttribute("style","font-size: 12pt");
theNewCell1 = theNewRow.insertCell(1);
theNewCell1.innerHTML = "<input type='text' class='doc' style='width:180px;' id='docNum0'/>";
theNewCell1.setAttribute("style","padding-left: 10px");
theNewCell2 = theNewRow.insertCell(2);
theNewCell2.innerHTML = "Approver Email";
theNewCell2.setAttribute("style","font-size: 12pt");
theNewCell2.setAttribute("style","padding-left: 10px");
theNewCell3 = theNewRow.insertCell(3);
theNewCell3.innerHTML = "<input type='text' class='rev' style='width:180px;' id='rev0'/> <input class='minusThing' type='button' style='font-size:10px' value='- '/>";
theNewCell3.setAttribute("style","padding-left: 0px");
node.appendChild( theNewRow );
// restore old arrays and add the id tags to the fields just added
docs = document.getElementsByClassName("doc");
revs = document.getElementsByClassName("rev");
for (n=0; n < idx; n++) {
docs[n].value = saveDocs[n];
revs[n].value = saveRevs[n];
}
docs[idx].id = "docNum" + idx;
revs[idx].id = "rev" + idx;
}
//for Loop the entries
function myfunction() {
alert('Inside Function')
var values = "";
for (n=0; n <= idx; n++)
{
var doc = document.getElementById("docNum"+n).value;
var rev = document.getElementById("rev"+n).value;
//alert(doc+rev);
//Call VbScript Sub and pass value
PassValues(doc,rev);
```

If you've removed all the docs, document.getElementsByClassName("doc"); is going to return an empty array. If you're incrementing idx before your loop, the loop will execute once and try to access docs[0], which is undefined.

Related

Unable to parse json using javascript

I have a json which i'm trying to parse it using javascript. Iteration count and the pages getting appended to it are going to be dynamic.
Expected Result
Just like the above image i'm able to take dynamic iteration keys from the below mentioned json.
Iteration.json
{
"count":[
{
"iteration1":[
{
"PageName":"T01_Launch"
},
{
"PageName":"T02_Login"
}
]
},
{
"iteration2":[
{
"PageName":"T01_Launch"
},
{
"PageName":"T02_Login"
}
]
}
]
}
When i click on iteration it has to populate the corresponding pagenames for that particular iteration as shown in expected result image. But what i get actually is (refer the image below):
Please find the code that i tried:
var pagenamearray = [];
$.getJSON("iteration.json", function(json) {
var hits = json.count;
var iterations, tnname, iteration;
for (var k in hits) {
var value;
if (hits.hasOwnProperty(k)) {
value = hits[k];
var iteratearray = [];
for (var j in value) {
if (value.hasOwnProperty(j)) {
j;
var check = value[j];
for (var i in check) {
if (check.hasOwnProperty(i)) {
var test = check[i];
for (var t in test) {
if (test.hasOwnProperty(t)) {
var pagename = JSON.stringify(t)
var arr = []
if (pagename.includes("PageName")) {
//alert("Key is " +pagename + ", value is" + JSON.stringify(test[t]));
for (var it = 0; it < hits.length; it++) {
if ((Object.keys(hits[it])).includes(j)) {
var pagenamevalue = test[t];
arr[it] = [];
arr.push(pagenamevalue);
}
}
}
//alert(arr)
}
pagenamearray.push(arr);
}
}
}
}
var row = document.createElement('div');
row.setAttribute("class", "row");
row.setAttribute("id", j)
var gridWidth = document.createElement('div');
gridWidth.setAttribute("class", "col-lg-12");
var panelRoot = document.createElement('div');
panelRoot.setAttribute("class", "panel panel-default");
var panelHeading = document.createElement('div');
panelHeading.setAttribute("class", "panel-heading");
var heading3 = document.createElement('a');
heading3.setAttribute("class", "panel-title");
var icon = document.createElement('i');
icon.setAttribute("class", "fa fa-long-arrow-right fa-fw");
heading3.appendChild(icon);
heading3.innerHTML = j;
heading3.setAttribute("onclick", "doit('" + j + "');");
panelHeading.appendChild(heading3);
/* var panelBody=document.createElement('div');
panelBody.setAttribute("class","panel-body");
panelBody.setAttribute("id","panellinks");*/
panelRoot.appendChild(panelHeading);
// panelRoot.appendChild(panelBody)
gridWidth.appendChild(panelRoot);
row.appendChild(gridWidth);
document.getElementById("analysis").appendChild(row);
}
}
}
});
function doit(value) {
var ul = document.getElementById(value);
if (ul != undefined) {
$("#" + "expandlinks").remove();
$("#" + value + value).remove();
}
var accordion = document.getElementById(value);
var panelBody = document.createElement('div');
panelBody.setAttribute("class", "panel-body");
panelBody.setAttribute("id", "expandlinks")
var tablediv = document.createElement('div')
var tablelink = document.createElement('a');
tablediv.appendChild(tablelink);
var graphdiv = document.createElement('div')
var graphlink = document.createElement('a');
graphdiv.appendChild(graphlink);
var recommndiv = document.createElement('div');
var recommendlink = document.createElement('a');
recommndiv.appendChild(recommendlink)
//alert(pagenamearray.length)
tablelink.innerHTML = pagenamearray;
/*graphlink.innerHTML="Timeline View";
recommendlink.innerHTML="Recommendations";*/
panelBody.appendChild(tablediv);
panelBody.appendChild(recommndiv);
panelBody.appendChild(graphdiv);
accordion.appendChild(panelBody);
}
Any advise on how to achieve this would be of great help. Thanks in advance.
I think the problem is how you assign the pagenamearray to tablelink.innerHTML. This converts the array to a string, converting all elements in the array to a string too and separating them by a comma each. However, your pagenamearray contains some empty arrays too; these will convert to an empty string in the process, but will still have a comma before and after them.
In your example code above, the pagenamearray will end up with a value of [[[],"T01_Launch"],[[],"T02_Login"],[null,[],"T01_Launch"],[null,[],"T02_Login"]] - when converted to a String, this will result in ",T01_Launch,,T02_Login,,,T01_Launch,,,T02_Login". So instead of assigning it to the innerHTML value directly, you'll first have to filter out the empty arrays and null values.

TypeError: Cannot read property "length" from undefined variables

I have worked with code that pulls table information off a site and then places into Google Sheets. While this had worked great for months, it has come to my attention that is has randomly stopped working.
I am getting the message "TypeError: Cannot read property "length" from undefined." From code:
for (var c=0; c<current_adds_array.length; c++) {
I have done extensive searching but cannot come to conclusion as to what is wrong.
Full code seen here:
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Get Data')
.addItem('Add new dispatch items','addNewThings')
.addToUi();
}
function addNewThings() {
// get page
var html = UrlFetchApp.fetch("#").getContentText();
// bypass google's new XmlService because html isn't well-formed
var doc = Xml.parse(html, true);
var bodyHtml = doc.html.body.toXmlString();
// but still use XmlService so we can use getDescendants() and getChild(), etc.
// see: https://developers.google.com/apps-script/reference/xml-service/
doc = XmlService.parse(bodyHtml);
var html = doc.getRootElement();
// a way to dig around
// Logger.log(doc.getRootElement().getChild('form').getChildren('table'));
// find and dig into table using getElementById and getElementsByTagName (by class fails)
var tablecontents = getElementById(html, 'formId:tableExUpdateId');
// we could dig deeper by tag name (next two lines)
// var tbodycontents = getElementsByTagName(tablecontents, 'tbody');
// var trcontents = getElementsByTagName(tbodycontents, 'tr');
// or just get it directly, since we know it's immediate children
var trcontents = tablecontents.getChild('tbody').getChildren('tr');
// create a nice little array to pass
var current_adds_array = Array();
// now let's iterate through them
for (var i=0; i<trcontents.length; i++) {
//Logger.log(trcontents[i].getDescendants());
// and grab all the spans
var trcontentsspan = getElementsByTagName(trcontents[i], 'span');
// if there's as many as expected, let's get values
if (trcontentsspan.length > 5) {
var call_num = trcontentsspan[0].getValue();
var call_time = trcontentsspan[1].getValue();
var rptd_location = trcontentsspan[2].getValue();
var rptd_district = trcontentsspan[3].getValue();
var call_nature = trcontentsspan[4].getValue();
var call_status = trcontentsspan[5].getValue();
//saveRow(call_num, call_time, rptd_location, rptd_district, call_nature, call_status);
current_adds_array.push(Array(call_num, call_time, rptd_location, rptd_district, call_nature, call_status));
}
}
saveRow(current_adds_array);
}
//doGet();
function saveRow(current_adds_array) {
// load in sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// find the current last row to make data range
var current_last_row = sheet.getLastRow();
var current_last_row_begin = current_last_row - 50;
if (current_last_row_begin < 1) current_last_row_begin = 1;
if (current_last_row < 1) current_last_row = 1;
//Logger.log("A"+current_last_row_begin+":F"+current_last_row);
var last_x_rows = sheet.getRange("A"+current_last_row_begin+":F"+current_last_row).getValues();
var call_num, call_time, rptd_location, rptd_district, call_nature, call_status;
// iterate through the current adds array
for (var c=0; c<current_adds_array.length; c++) {
call_num = current_adds_array[c][0];
call_time = current_adds_array[c][1];
rptd_location = current_adds_array[c][2];
rptd_district = current_adds_array[c][3];
call_nature = current_adds_array[c][4];
call_status = current_adds_array[c][5];
// find out if the ID is already there
var is_in_spreadsheet = false;
for (var i=0; i<last_x_rows.length; i++) {
//Logger.log(call_num+" == "+last_15_rows[i][0]);
if (call_num == last_x_rows[i][0] && call_time != last_x_rows[i][1]) is_in_spreadsheet = true;
}
Logger.log(is_in_spreadsheet);
//Logger.log(last_15_rows.length);
if (!is_in_spreadsheet) {
Logger.log("Adding "+call_num);
sheet.appendRow([call_num,call_time,rptd_location,rptd_district,call_nature,call_status]);
}
}
}
function getElementById(element, idToFind) {
var descendants = element.getDescendants();
for(i in descendants) {
var elt = descendants[i].asElement();
if( elt !=null) {
var id = elt.getAttribute('id');
if( id !=null && id.getValue()== idToFind) return elt;
}
}
}
function clearRange() {
//replace 'Sheet1' with your actual sheet name
var sheet = SpreadsheetApp.getActive().getSheetByName('Sheet1');
sheet.getRange('A2:F').clearContent();}
function getElementsByTagName(element, tagName) {
var data = [];
var descendants = element.getDescendants();
for(i in descendants) {
var elt = descendants[i].asElement();
if( elt !=null && elt.getName()== tagName) data.push(elt);
}
return data;
}
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange("C:C");
range.setValues(range.getValues().map(function(row) {
return [row[0].replace(/MKE$/, " Milwaukee, Wisconsin")];
}));
Please be careful when instantiating a new array. You are currently using var current_adds_array = Array(). You're not only missing the new keyword, but also, this constructor is intended to instantiate an Array with an Array-like object.
Try changing this to var current_adds_array = []

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 to use an event object to dispaly information about a DOM element

I want to be able to click on a box (the boxes are created through code, and receive values from a form) in the webpage and display information about the box. I am working on a display() function that uses an event object and an alert to display information about the box. So far, I've had multiple odd failures in my attempt to do this, which leads me to believe that I'm not accessing object attributes correctly. I'm a beginner, so this could be really obvious, but thanks for the help.
constructor function:
function Box (counter, name, color, number, coordinates) {
this.counter = counter;
this.name = name;
this.color = color;
this.number = number;
this.coordinates = coordinates;
}
Global variables:
var boxes = [];
var counter = 0;
Init function:
function init() {
var generateButton = document.getElementById("generateButton");
generateButton.onclick = getBoxValues;
var clearButton = document.getElementById("clearButton");
clearButton.onclick = clear;
}
Function that gets values from the form:
function getBoxValues() {
var nameInput = document.getElementById("name");
var name = nameInput.value;
var numbersArray = dataForm.elements.amount;
for (var i = 0; i < numbersArray.length; i++) {
if (numbersArray[i].checked) {
number = numbersArray[i].value;
}
}
var colorSelect = document.getElementById("color");
var colorOption = colorSelect.options[colorSelect.selectedIndex];
var color = colorOption.value;
if (name == null || name == "") {
alert("Please enter a name for your box");
return;
} else {
var newbox = new Box(counter, name, color, number, "coordinates");
boxes.push(newbox);
counter++;
/*for(m = 0; m < boxes.length; m++) {
counter.newbox = boxes[m];
}*/
}
addBox(newbox);
var data = document.getElementById("dataForm");
data.reset();
}
function that assigns attributes to the boxes:
function addBox(newbox) {
for (var i = 0; i < newbox.number; i++) {
var scene = document.getElementById("scene");
var div = document.createElement("div");
div.className += " " + "box";
div.innerHTML += newbox.name;
div.style.backgroundColor = newbox.color;
var x = Math.floor(Math.random() * (scene.offsetWidth-101));
var y = Math.floor(Math.random() * (scene.offsetHeight-101));
div.style.left = x + "px";
div.style.top = y + "px";
scene.appendChild(div);
div.onclick = display;
//console.log(newbox);
//shows all of the property values of newbox in the console
//console.log(div); shows that it is an object in the console
//console.log(div.hasAttribute(number)); says false
}
}
display function:
function display(e) {
// alert(e.target); says its an html object
//alert(e.target.className); works - says "box"
//alert(e.target.hasAttribute(name)); says false
}
I've included some of the things i've found in comments.
The event object only gives you the name not a reference to the element. So... a couple of things.
First if you want to be browser agnostic you want something like (e.srcElement is for IE):
var x = e.target||e.srcElement;
Then get a reference to the element and do what you want:
var refToElement = document.getElementById(x.id);

Javascript function not recognizing id in getElementById

I am adding a row to a table, and attached an ondblclick event to the cells. The function addrow is working fine, and the dblclick is taking me to seltogg, with the correct parameters. However, the var selbutton = document.getElementById in seltogg is returning a null. When I call seltogg with a dblclick on the original table in the document, it runs fine. All the parameters "selna" have alphabetic values, with no spaces, special characters, etc. Can someone tell me why seltogg is unable to correctly perform the document.getElementById when I pass the id from addrow; also how to fix the problem.
function addrow(jtop, sel4list, ron4list) {
var tablex = document.getElementById('thetable');
var initcount = document.getElementById('numrows').value;
var sel4arr = sel4list.split(",");
var idcount = parseInt(initcount) + 1;
var rowx = tablex.insertRow(1);
var jtop1 = jtop - 1;
for (j = 0; j <= jtop1; j++) {
var cellx = rowx.insertCell(j);
cellx.style.border = "1px solid blue";
var inputx = document.createElement("input");
inputx.type = "text";
inputx.ondblclick = (function() {
var curj = j;
var selna = sel4arr[curj + 2];
var cellj = parseInt(curj) + 3;
inputx.id = "cell_" + idcount + "_" + cellj;
var b = "cell_" + idcount + "_" + cellj;
return function() {
seltogg(selna, b);
}
})();
cellx.appendChild(inputx);
} //end j loop
var rowCount = tablex.rows.length;
document.getElementById('numrows').value = rowCount - 1; //dont count header
} //end function addrow
function seltogg(selna, cellid) {
if (selna == "none") {
return;
}
document.getElementById('x').value = cellid; //setting up for the next function
var selbutton = document.getElementById(selna); //*****this is returning null
if (selbutton.style.display != 'none') { //if it's on
selbutton.style.display = 'none';
} //turn it off
else { //if it's off
selbutton.style.display = '';
} //turn it on
} //end of function seltogg
You try, writing this sentence:
document.getElementById("numrows").value on document.getElementById('numrows').value
This is my part the my code:
contapara=(parseInt(contapara)+1);
document.getElementById("sorpara").innerHTML+="<li id=\"inputp"+contapara+"_id\" class=\"ui-state-default\"><span class=\"ui-icon ui-icon-arrowthick-2-n-s\"></span>"+$('#inputp'+contapara+'_id').val()+"</li>";
Look you have to use this " y not '.
TRY!!!!

Categories

Resources