I have a website that gets locations out of a MySQL database and passes it to a JavaScript function as a JSON object. The JavaScript function dynamically creates tables for each row returned from the database. Each location object returned includes a latitude and longitude and I want to create a Google map for each object. I can successfully create 1 map on the page using data returned from the database but when I add the map creation code to the loop that builds tables it begins throwing this error:
TypeError: Cannot read property 'offsetWidth' of null
I have gone through other questions that people have posted about this error. The two causes that it can have are either (1) the <div> I am trying to add the map to doesn't exist, or (2) I am trying to display the map before it is created. I know that the <div>s exist as they exist in the page when it is displayed. I am not sure how to check for or fix the other issue.
This is my JavaScript that retrieves data and builds the tables:
google.maps.event.addDomListener(window, "load");
//THIS FUNCTIONS BUILD THE MAPS
//PASS LAT, LONG, AND ID FOR DIV
function initializeMap(latitude,longitude, mapID)
{
var myCenter = new google.maps.LatLng(latitude, longitude);
var mapProp =
{
center:myCenter,
zoom: 12,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map=new google.maps.Map(document.getElementById(mapID), mapProp);
var marker=new google.maps.Marker({
position:myCenter,
});
marker.setMap(map);
}
function removeTable()
{
$("#tableID").remove();
}
/*
ajaxRequest variable receives and parses a JSON object into a 2 dimensional array
an example of what a single row returned will look like: [["2","Alexandra","33 GRANT STREET","ALEXANDRA","3714","57721040","-37.18859863281250000000","145.70799255371094000000","","security"]]
when trying to access elements in the array using a loop, columns are as follows:
ajaxRequest[i][0] = database id
ajaxRequest[i][1] = name
ajaxRequest[i][2] = address
ajaxRequest[i][3] = suburb
ajaxRequest[i][4] = postcode
ajaxRequest[i][5] = phone
ajaxRequest[i][6] = latitude
ajaxRequest[i][7] = longitude
ajaxRequest[i][8] = description
ajaxRequest[i][9] = service_type
*/
function search(option)
{
var ajaxRequest;
try{
// Opera 8.0+, Firefox, Safari
ajaxRequest = new XMLHttpRequest();
}catch (e){
// Internet Explorer Browsers
try{
ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP");
}catch (e) {
try{
ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP");
}catch (e){
// Something went wrong
alert("Your browser broke!");
return false;
}
}
}
/*
1 = unsafe
2 = depressed
3 = sad
*/
if(option == 1)
{ajaxRequest.open("GET", "securitymodel.php", true);}
if(option == 2)
{ajaxRequest.open("GET", "depressedModel.php", true);}
if(option == 3)
{ajaxRequest.open("GET", "sadmodel.php", true);}
ajaxRequest.send(null);
// Create a function that will receive data
// sent from the server and will update
// div section in the same page.
var ajaxResult = 1;
ajaxRequest.onreadystatechange = function()
{
if(ajaxRequest.readyState == 4)
{
var ajaxDisplay = document.getElementById('ajaxDiv');
//ajaxDisplay.innerHTML = ajaxRequest.responseText;
ajaxResult = JSON.parse(ajaxRequest.responseText);
if(ajaxResult.length > 0)
{
//IF SOMETHING IS RETURNED BEGIN BUILDING THE TABLE
var tableLocation = document.getElementById('suggestionTable');
var tableArea = document.createElement('table');
tableArea.id = 'tableID';
for(var i = 0; i < ajaxResult.length; i++)
{ //create inner row
var innerRow = document.createElement('tr');
var innerTD = document.createElement('td');
//WE MUST GO DEEPER!!!
var innerTable = document.createElement('table');
var superInnerTD = document.createElement('td');
var secondSuperInnerTD = document.createElement('td');
//row 1
var nameTR = document.createElement('tr');
var nameHead = document.createElement('td');
var name = document.createTextNode('Name:');
nameHead.appendChild(name);
nameTR.appendChild(nameHead);
var nameTD = document.createElement('td');
var nameText = document.createTextNode(ajaxResult[i][1]);
nameTD.appendChild(nameText);
nameTR.appendChild(nameTD);
superInnerTD.appendChild(nameTR);
//row 2
var descTR = document.createElement('tr');
var descHead = document.createElement('td');
var desc = document.createTextNode('Description:');
descHead.appendChild(desc);
descTR.appendChild(descHead);
var descTD = document.createElement('td');
var descText = document.createTextNode(ajaxResult[i][8]);
descTD.appendChild(descText);
descTR.appendChild(descTD);
superInnerTD.appendChild(descTR);
//row 3
var addTR = document.createElement('tr');
var addressHead = document.createElement('td');
var address = document.createTextNode('Address:');
addressHead.appendChild(address);
addTR.appendChild(addressHead);
var addTD = document.createElement('td');
var addressText = document.createTextNode(ajaxResult[i][2]);
addTD.appendChild(addressText);
addTR.appendChild(addTD);
superInnerTD.appendChild(addTR);
//row 4
var subTR = document.createElement('tr');
var suburbHead = document.createElement('td');
var suburb = document.createTextNode('Suburb:');
suburbHead.appendChild(suburb);
subTR.appendChild(suburbHead);
var subTD = document.createElement('td');
var subText = document.createTextNode(ajaxResult[i][3]);
subTD.appendChild(subText);
subTR.appendChild(subTD);
superInnerTD.appendChild(subTR);
//row 5
var postTR = document.createElement('tr');
var postcodeHead = document.createElement('td');
var postcode = document.createTextNode('Postcode:');
postcodeHead.appendChild(postcode);
postTR.appendChild(postcodeHead);
var postTD = document.createElement('td');
var postText = document.createTextNode(ajaxResult[i][4]);
postTD.appendChild(postText);
postTR.appendChild(postTD);
superInnerTD.appendChild(postTR);
//row 6
var phoneTR = document.createElement('tr');
var phoneHead = document.createElement('td');
var phone = document.createTextNode('Phone:');
phoneHead.appendChild(phone);
phoneTR.appendChild(phoneHead);
var phoneTD = document.createElement('td');
var phoneText = document.createTextNode(ajaxResult[i][5]);
phoneTD.appendChild(phoneText);
phoneTR.appendChild(phoneTD);
superInnerTD.appendChild(phoneTR);
//The divContainer requires an id
//ID IS AUTOMATICALLY GENERATED BY CONACTENATING THE NAME AND ADDRESS TOGETHER
var mapID = ajaxResult[i][1]+ajaxResult[i][2];
var divContainer = document.createElement("div");
divContainer.setAttribute("id", mapID);
secondSuperInnerTD.appendChild(divContainer);
initializeMap(ajaxResult[i][6],ajaxResult[i][7],mapID);
innerTable.appendChild(superInnerTD);
innerTable.appendChild(secondSuperInnerTD);
innerTD.appendChild(innerTable);
innerRow.appendChild(innerTD);
tableArea.appendChild(innerRow);
}
tableLocation.appendChild(tableArea);
}
}
}
}
An example of a completed table looks like:
We want to put the map in the <td> on the right.
To reiterate, the map generation works when we are trying to build 1 map in a <div> that is coded in html on the page. When we try to create several maps inside <div>s that are dynamically created it fails.
The call to initialize the map happens before the div is added to the DOM.
initializeMap(ajaxResult[i][6],ajaxResult[i][7],mapID);
The above line is called before the following line :
tableLocation.appendChild(tableArea);
The map divs that you create dynamically are added to the page when this line is executed. Due to this you are getting the error.
One workaround would be to use settimeout so that the initialize function is called after the map divs are added to the DOM.
setTimeout(function(){ initializeMap(ajaxResult[i][6],ajaxResult[i][7],mapID); }, 500);
Another option is to push the data into an array and iterate that array after the tableLocation.appendChild(tableArea); line and then call the intializeMap function using that data
Related
I have a script that on Form submit takes the data from the spreadsheet and creates a copy of a template and populates the google docs. I am trying to accomplish the same thing from google form to google slides.
First script I use for the google forms to google docs. The second script is my attempt of using the same principles and applying to google slides. My issue is I'm getting an error saying TypeError: values.forEach is not a function (line 109, file "Code") in relation to values.forEach(function(page). Any suggestions on how I could go about solving this?
Google Form to Google Sheets
function autoFillGoogleDocFromForm(e) {
var timestamp = e.values[0];
var address = e.values[1];
var image = e.values[2];
var price = e.values[3];
var summary = e.values[4];
var type = e.values[5];
var year_built = e.values[6];
var bed = e.values[7];
var bath = e.values[8];
var home_size = e.values[9];
var lot_size = e.values[10];
var occupancy = e.values[11];
var templateFile = DriveApp.getFileById("xxxxxxxx");
var templateResponseFolder = DriveApp.getFolderById("yyyyyyyyyy")
var copy = templateFile.makeCopy( address , templateResponseFolder);
var doc = DocumentApp.openById(copy.getId())
var body = doc.getBody();
body.replaceText("{{address}}", address);
body.replaceText("{{price}}", price);
body.replaceText("{{summary}}", summary);
body.replaceText("{{type}}", type);
body.replaceText("{{year_built}}", year_built);
body.replaceText("{{beds}}", bed);
body.replaceText("{{baths}}", bath);
body.replaceText("{{home_size}}", home_size);
body.replaceText("{{lot_size}}", lot_size);
body.replaceText("{{occupancy}}", occupancy);
doc.saveAndClose;
}
Google Form to Google Slides
function generateLandingPagesReport(){
var dataSpreadsheetUrl = "https://docs.google.com/spreadsheets/xxxxxxxxx/edit"
var Presentation_ID = "xxxxxxxxxxxxxx";
var ss = SpreadsheetApp.openByUrl(dataSpreadsheetUrl);
var deck = SlidesApp.openById(Presentation_ID);
var sheet = ss.getSheetByName('Sheet1');
var values = sheet.getRange('A1:J17').getValues;
var slides = deck.getSlides();
var templateSlide = slides[1];
var presLength = slides.length;
values.forEach(function(page){
values.forEach(function(page){
if(page[0]){
var landingPage = page[0];
var sessions = page[1];
var newSessions = page[2];
}
templateSlide.duplicate(); // duplicate the template page
/*slides = deck.getSlides(); // update the slides array for indexes and length*/
newSlide = slides[2]; // declare the new page to update
var shapes = (newSlide.getShapes());
shapes.forEach(function(shape){
shape.getText().replaceAllText('{{landing page}}', landingPage);
shape.getText().replaceAllText('{{sessions}}', sessions);
shape.getText().replaceAllText('{{new sessions}}',newSessions);
});
presLength = slides.length;
newSlide.move(presLength);
//end our condition statement
}); //close our loop of values
//remove template slide
templateSlide.remove();
});
}
You're missing the parenthesis when calling the getValue() method.
Change this:
var values = sheet.getRange('A1:J17').getValues;
To this:
var values = sheet.getRange('A1:J17').getValues();
Not exactly what I was looking for but this uses the first Row to identify the tag inside the Google slides template like {{title}} and replaces that with the value in the second row of the sheet
function createPresentation() {
var templateFile = DriveApp.getFileById("1YVEA4WtU1Kf6nZRgHpwnKBIR-V6rRN6s9zCdOQDkWNI");
var templateResponseFolder = DriveApp.getFolderById("1k7rcfXODij4o4arSULuKZUHbit1m_X64");
var copy = templateFile.makeCopy("New" , templateResponseFolder);
var Presentation = SlidesApp.openById(copy.getId());
var values = SpreadsheetApp.getActive().getDataRange().getValues();
values.forEach(function(row) {
var templateVariable = row[0];
var templateValue = row[1];
Presentation.replaceAllText(templateVariable, templateValue);
});
}
After you have copy the template page, you work on it and try to do replace.
However, change may be pending such that newSlide = slides[2]; give undefined.
You may need to try saveAndClose() before performing any actions.
templateSlide.duplicate(); // duplicate the template page
/*slides = deck.getSlides(); // update the slides array for indexes and length*/
/* flush the presentation */
deck.saveAndClose();
deck = SlidesApp.openById(Presentation_ID);
slides = deck.getSlides();
newSlide = slides[2]; // declare the new page to update
var shapes = (newSlide.getShapes());
shapes.forEach(function(shape){
shape.getText().replaceAllText('{{landing page}}', landingPage);
shape.getText().replaceAllText('{{sessions}}', sessions);
shape.getText().replaceAllText('{{new sessions}}',newSessions);
});
I am trying to print the address and details of my clinics in various locations. However, when i try to do that it is only printing the first element in my div.
Here is my code
var markerNodes = xml.documentElement.getElementsByTagName("marker");
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < markerNodes.length; i++) {
var id = markerNodes[i].getAttribute("id");
var locname = markerNodes[i].getAttribute("locationName");
var locaddress = markerNodes[i].getAttribute("locationAddress1");
var address = markerNodes[i].getAttribute("locationAddress1");
var distance = parseFloat(markerNodes[i].getAttribute("distance"));
var servicename = markerNodes[i].getAttribute("serviceName");
var clinicfname= markerNodes[i].getAttribute("clinicFname");
var cliniclname= markerNodes[i].getAttribute("clinicLname");
var clinicname= clinicfname + ' ' + cliniclname ;
var clinicAddress= markerNodes[i].getAttribute("clinicAddress");
var clinicCity= markerNodes[i].getAttribute("clinicCity");
var clinicPhone= markerNodes[i].getAttribute("clinicPhone");
var cname= markerNodes[i].getAttribute("cname");
var latlng = new google.maps.LatLng(
parseFloat(markerNodes[i].getAttribute("locationLat")),
parseFloat(markerNodes[i].getAttribute("locationLong")));
document.getElementById('details_name').innerHTML = clinicname;
//console.log (parseFloat(markerNodes[i].getAttribute("locationLong")));
createdetails(clinicname,clinicAddress)
bounds.extend(latlng);
}
In above code am calling a function name createdetails
function createdetails(clinicname,clinicAddress)
{
document.getElementById("details_name").innerHTML=clinicname;
document.getElementById("details_address").innerHTML=clinicAddress;
}
But this div is priniting only first name and first addrees.It have 9 diffrent values for name and address.When i consoled it,it prints.
What is the problem here?
When you are calling document.getElementById("details_name").innerHTML = ..., you are overwriting the current value. Maybe you should append the new name to the existing content with +=:
function createdetails(clinicname,clinicAddress)
{
document.getElementById("details_name").innerHTML+=clinicname;
document.getElementById("details_address").innerHTML+=clinicAddress;
}
I'm using Google Sheets and received an error while saving "The coordinates of the target range are outside the dimensions of the sheet". I checked the script and the issue is with line 15. Here is the error "TypeError: Cannot call method "getLastColumn" of null. (line 15, file "Code")" How do I fix this?
function clear() {
var sheet = SpreadsheetApp.getActive().getSheetByName('Form'); // Change to your Sheet tab name
sheet.getRange('D11:G35').clearContent(); // Change to the range you would like to clear
sheet.getRange('C3:C7').clearContent();
}
function save(){
var source_sheet = SpreadsheetApp.getActive().getSheetByName('Form');
var agent_name= source_sheet.getRange('C3').getValue();
var dest_sheet = SpreadsheetApp.getActive().getSheetByName(agent_name);
//add x number of new columns each save
var head_data = source_sheet.getRange('B3:E7');
var body_data = source_sheet.getRange('B9:G35'); //change this range as needed for new scoring parameters
var col = dest_sheet.getLastColumn(); + 1;
var dest_data = dest_sheet.getRange(1, col);
head_data.copyTo(dest_data, {contentsOnly: true});
dest_data = dest_sheet.getRange(6, col);
body_data.copyTo(dest_data, {contentsOnly:true});
}
function create_agent_sheets(){
var agent_sheet = SpreadsheetApp.getActive().getSheetByName("Agents");
var row = 1;
var col = 1;
while(!agent_sheet.getRange(row, col).isBlank()){
var cell = agent_sheet.getRange(row,col);
var name = cell.getValue();
SpreadsheetApp.getActive().insertSheet(name);
row++;
}
agent_sheet.activate();
}
function delete_agent_sheets(){
var agent_sheet = SpreadsheetApp.getActive().getSheetByName("Agents");
var row = 1;
var col = 1;
while(!agent_sheet.getRange(row, col).isBlank()){
var cell = agent_sheet.getRange(row,col);
var name = cell.getValue();
var sheet = SpreadsheetApp.getActive().getSheetByName(name);
SpreadsheetApp.getActive().deleteSheet(sheet);
row++;
}
agent_sheet.activate();
}
The error is preventing me from Saving the document.
I'm working on a script that generates a calendar event from a sheet in a google spreadsheet. after debugging the code I come up with no errors but when I run the code I get this "Cannot call method 'setTitle' of null". I have been unsuccessful in my attempts in troubleshooting and do not fully understand the substance of this error. Can someone help me understand what I'm doing wrong here?
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Export Events",
functionName : "exportEvents"
}];
ss.addMenu("Calendar Actions", entries);
};
/**
* Export events from spreadsheet to calendar
*/
function exportEvents() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
var headerRows = 389; // Number of rows of header info (to skip)
var range = sheet.getDataRange();
var data = range.getValues();
var calId = "somewhere#farfaraway.com";
var cal = CalendarApp.getCalendarById(calId);
for (i=0; i<data.length; i++) {
if (i < headerRows) continue; // Skip header row(s)
var row = data[i];
var date = new Date(row[11]); // column L
var title = row[9]; // Column J
var estimator = row[6];
var tstart = new Date(row[11]);
tstart.setDate(date.getDate());
tstart.setMonth(date.getMonth());
tstart.setYear(date.getYear());
var tstop = new Date(row[11]);
tstop.setDate(date.getDate());
tstop.setMonth(date.getMonth());
tstop.setYear(date.getYear());
var loc = row[10]; // Column K
var desc = row[13]; // Column N
var id = row[0]; // Column A == eventId
// Check if event already exists, update it if it does
try {
var calev = cal.getEventSeriesById(id);
}
catch (e) {
// do nothing - we just want to avoid the exception when event doesn't exist
}
if (estimator == "a person" && !calev) {
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"), {description:desc,location:loc});
var newEvent = cal.createEvent(title, tstart, tstop, {description:desc,location:loc}).getId();
row[0] = newEvent; // Update the data array with event ID
}
else {
calev.setTitle(title);
calev.setDescription(desc);
calev.setLocation(loc);
// event.setTime(tstart, tstop); // cannot setTime on eventSeries.
// ... but we CAN set recurrence!
var recurrence = CalendarApp.newRecurrence().addDailyRule().times(1);
event.setRecurrence(recurrence, tstart, tstop);
}
debugger;
}
// Record all event IDs to spreadsheet
range.setValues(data);
}
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 = []