I'm attempting to modify a Google maps API v3 direction script. I thought I had a firm grasp of combining variables etc but then I ran into this problem:
function calcRoute() {
var end = document.getElementById("start").value;
var street = document.getElementById("street").value;
var city = document.getElementById("city").value;
var state = document.getElementById("state").value;
var zip = document.getElementById("zip").value;
var start = street + ' ' + city + ' ' + state + ' ' + zip;
var request = {
origin:start,
destination:end,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
If I create an input with an id of start and change
var start = document.getElementById("start").value;
the script works again. however I can't get my combined variable to work:
var start = street + ' ' + city + ' ' + state + ' ' + zip;
if i make a button to alert(start) it returns null... what am I doing wrong?
Update: Also of note,
if I run:
onClick="alert(end)"
while
<input id="end" name="destination" type="hidden" value="test" />
the alert returns "object HTMLInputElement" not "test" as it should.
If you want to alert the value of the "end" input you need to do:
onClick="alert(document.getElementById('end').value)"
As for your start being null problem, I don't believe that one of the variables was null, if I try this:
null + " " + null
I get "null null" (tested both on chrome and firefox).
And so, my question is: where do you try to access the "start" variable from? Is it from inside the function in which it was defined in or outside of it? You can't access that variable from outside the calcRoute function.
So if you are doing something like:
<input type="button" onclick="alert(start)" />
It's bound to fail, instead do something like this:
var start;
function calcRoute() {
var end = document.getElementById("start").value;
var street = document.getElementById("street").value;
var city = document.getElementById("city").value;
var state = document.getElementById("state").value;
var zip = document.getElementById("zip").value;
start = street + ' ' + city + ' ' + state + ' ' + zip;
.....
Related
I have never written in JavaScript before, and I'm sure it shows. This will likely make some of you cringe but its the best way I know how to parse and check the spreadsheet data. I need an email alert to go out when the date of calibration is less than a specified cutoff date. I've tried a few configurations, some send emails for every item regardless of the date comparison and some send nothing such as the following script. Please help me make this work! I'm sure its mostly syntax or lack of specification for certain data structures.
'''
function checkCal(){
// Fetch the equipment name, calibration date, and today's date
var ss = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1xKzfW5vX3-eDWKuKmc3R_xin4FMFKhDHaDAd7vdoaLE/edit#gid=0');
SpreadsheetApp.setActiveSpreadsheet(ss);
var calibrationDateRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Equipment").getRange("H2:H12").getValues();
var vendList = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Equipment").getRange("C2:C12").getValues();
var modelList = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Equipment").getRange("D2:D12").getValues();
var cutoffDate = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Emails").getRange("D1").getValue();
var shipped = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Equipment").getRange("I2:I12").getValues();
var notes = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Equipment").getRange("J2:J12").getValues();
var sn = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Equipment").getRange("E2:E12").getValues();
var loc = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Equipment").getRange("A2:A12").getValues();
// Check date
for (var i = 0; i < calibrationDateRange.length; i++){
var calDate = Date(calibrationDateRange[i].getValue());
//console.log('comparing' + calDate + ' to ' + cutoffDate);
if (calDate.getTime() <= cutoffDate.getTime() + shipped[i] == false){
// Fetch the email address
var emailRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Emails").getRange("B2");
var emailAddress = emailRange.getValue();
// Send Alert Email.
var message = 'Calibration due date is approaching for ' + vendList[i] + ' ' + modelList[i] + ' S/N: ' + sn[i] + ', located at ' + loc[i] + ', on ' + calDate[i] + '. Please reference the equipment spreadsheet to verify this date and the serial number of the referenced equipment. Note: ' + notes[i]; // body of email using associated variables
var subject = 'Equipment Calibration Alert';
MailApp.sendEmail(emailAddress, subject, message);
}
}
}
'''
Try it this way:
function checkCal() {
var ss = SpreadsheetApp.openByUrl('https://docs.google.com/spreadsheets/d/1xKzfW5vX3-eDWKuKmc3R_xin4FMFKhDHaDAd7vdoaLE/edit#gid=0');
const msh = ss.getSheetByName("Emails");
const esh = ss.getSheetByName("Equipment");
const evs = esh.getRange(2, 1, esh.getLastRow() - 1, esh.getLastColumn()).getValues();
const codt = new Date(msh.getRange("D1").getValue());
const emailAddress = msh.getRange(msh.getRange("B2").getValue()).getValue();
evs.forEach((r, i) => {
let calDate = new Date(r[7]);
if (calDate.valueOf() <= codt.valueOf() && !r[8]) {
let message = 'Calibration due date is approaching for ' + r[2] + ' ' + modelList[i] + ' S/N: ' + r[4] + ', located at ' + r[0] + ', on ' + calDate + '. Please reference the equipment spreadsheet to verify this date and the serial number of the referenced equipment. Note: ' + r[9];
var subject = 'Equipment Calibration Alert';
MailApp.sendEmail(emailAddress, subject, message);
}
});
}
<!DOCTYPE html>
<html>
<head>
<title> Location Test </title>
<link rel="shortcut icon" href="#">
</head>
<body>
<h1> Location </h1>
<label id = "Address"> </label>
<br>
<input type="button" value="Log Out" id="LogOut">
<script>
const logoutButton = document.getElementById("LogOut");
function getLocation() {
navigator.geolocation.getCurrentPosition(
function(Position) {
var currentdate = new Date();
document.getElementById("Address").innerHTML = document.getElementById("Address").textContent + "Last Sync: " + currentdate.getDate() + "/" +
(currentdate.getMonth() + 1) + "/" +
currentdate.getFullYear() + ". " +
currentdate.getHours() + ":" +
currentdate.getMinutes() + "." +
currentdate.getSeconds() + ". ";
document.getElementById("Address").innerHTML = document.getElementById("Address").textContent + "Latitude: " + Position.coords.latitude;
document.getElementById("Address").innerHTML = document.getElementById("Address").textContent + " Longitude: " + Position.coords.longitude;
document.getElementById("Address").innerHTML = document.getElementById("Address").textContent + " Accuracy: " + Position.coords.accuracy;
document.getElementById("Address").innerHTML = document.getElementById("Address").textContent + " Heading towards direction: " + Position.coords.heading;
document.getElementById("Address").innerHTML = document.getElementById("Address").textContent + " Speed: " + Position.coords.speed;
var api_key = '206170168bcf4fdf905d85a34f7b3d79';
var latitude = Position.coords.latitude;
var longitude = Position.coords.longitude;
var api_url = 'https://api.opencagedata.com/geocode/v1/json'
var request_url = api_url +
'?' +
'key=' + api_key +
'&q=' + encodeURIComponent(latitude + ',' + longitude) +
'&pretty=1' +
'&no_annotations=1';
var request = new XMLHttpRequest();
request.open('GET', request_url, true);
request.onload = function() {
if (request.status === 200) {
// Success!
var data = JSON.parse(request.responseText);
document.getElementById("Address").innerHTML = document.getElementById("Address").textContent + " Address: " + data.results[0].formatted; // print the location
} else if (request.status <= 500) {
// We reached our target server, but it returned an error
console.log("unable to geocode! Response code: " + request.status);
var data = JSON.parse(request.responseText);
console.log('error msg: ' + data.status.message);
} else {
console.log("server error");
}
};
request.onerror = function() {
console.log("unable to connect to server");
};
request.send(); // make the request
},
function(PositionError) {
document.getElementById("Latitude").innerHTML = "Could not get latitude";
document.getElementById("Longitude").innerHTML = "Could not get longitude";
})
}
getLocation();
setInterval(getLocation, 1000 * 60 * 5)
logoutButton.addEventListener("click", (e) => {
e.preventDefault();
window.location.href = "login.html";
})
</script>
</body>
</html>
So basically, what I want to do is create a new line at the end of the function. So each time I use setInterval, it creates a new line in the label. But I'm not sure how to. That way, every time it updates the location after 5 minutes, it prints it on a new line.
You can ignore the rest of what I say, I'm getting the error that my post is mostly code.
Just write a <br> tag. So change
+ " Address: "
to:
+ "<br> Address: "
As trincot stated, the inclusion of the <br> (line break) tag is the way to go as we want to create new lines directly in the address label. However, a code change is required because our newly appended line breaks will get rewritten when we re-call function getLocation().
Appended line breaks will vanish if we reinitialise our label's innerHTML with its previous textContent because textContent selects the message from the target and ignores nested HTML contents.
Thus, the best solution is to formulate the location before its inclusion to the address label.
// Get local date and time.
var currentdate = new Date();
var cd_date = currentdate.toLocaleDateString("en-UK");
var cd_time = currentdate.toLocaleTimeString("en-UK");
// Formulate location string.
var location = `
Last Sync: ${cd_date} - ${cd_time},
Latitude: ${Position.coords.latitude},
Longitude: ${Position.coords.longitude},
Accuracy: ${Position.coords.accuracy},
Heading towards direction: ${Position.coords.heading},
Speed: ${Position.coords.speed},
`.replace(/\s{2}/g, '').trim(); // Remove additional spaces.
...
if (request.status === 200) {
// Success!
var data = JSON.parse(request.responseText);
location += ` Address: "${data.results[0].formatted}".`;
// print the location
var elm_address = document.getElementById("Address");
elm_address.innerHTML += (elm_address.innerHTML.trim().length > 0) ? `<br>${location}` : location;
}
We want to include line breaks when we append additional location to the address label, so I decided to have a conditional statement before appending stage.
elm_address.innerHTML += will append the location after
following condition (elm_address.innerHTML.trim().length > 0).
The condition checks if address label is empty.
? `<br>${location}` : location;
When the condition's result is negative, location is appended without a line break. Otherwise, a line break is included.
I am having trouble passing a value from a Google Spreadsheet to a Javascript function on the HTML.
code.gs
function getSiteCoords()
{
var emailA = Session.getActiveUser().getEmail();
var employeesheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Employees") // data pertaining to employees
var numRows=1;
while(employeesheet.getRange("A"+numRows+":A"+numRows).getValue() != "") //this will count the number of rows that are filled
{
if(employeesheet.getRange("A"+numRows).getValue()===emailA)
{
let coords = employeesheet.getRange("E"+numRows).getValue();
return coords;
}
numRows = numRows+1;
}
return "";
}
index.html
function checkPosition(position) {
console.log("Latitude: " + position.coords.latitude +
" Longitude: " + position.coords.longitude);
var lat= 54.978 ;
var long=-1.5622;
var coords = google.script.run.getSiteCoords();
console.log("Site Coords " + coords);
let calc= Math.sqrt(Math.pow(position.coords.latitude - lat , 2) + Math.pow(position.coords.longitude - long , 2));
console.log("calc: "+ calc);
if(calc>0.005)
window.location.replace("https://google.com");
}
No matter what, the coords on index.html returns undefined.
The issue is: I can't find a way to return the value for 'Course' because each form submission generates a new row where the name of the course is spread over columns E to M (column 4 through 12).
In each row, there is only one 'Course' name in one of the columns from E to M (e.g only in F) and all other columns are blank. (Users can only select one course and all the other columns will be blank. I have to categorize the courses into the 9 columns because of the page breaks in order to split the sheer number of options that users select the course from.) How do I return the value of the only non blank cell from E to M which will be entered in the email ?
I was advised to insert the entire findCourse function inside of the sendEmail function before any of the other code. I did so but I have still been receiving failure notifications of the Google App Scripts: TypeError: Cannot read property "values" from undefined. (line 14, file "Code") (referring to var value = e.values[i])
The full code below:
function sendEmail(e) {
function findCourse (e){
var courseToTake;
//loop through values
for ( var i = 4; i <=12; i ++){
//pull value into variable
var value = e.values[i];
if (value != undefined){
//if we find an actual string value, set the course to take variable
courseToTake = value;
}
}
return courseToTake;
}
var Name = e.namedValues["Full name as appear in NRIC"];
var Course = findCourse();
var Start = e.values[14];
var End = e.values[15];
var StartTime = e.values[24];
var EndTime = e.values[25];
var Details = e.values[13];
var Cost = e.values[17];
var Email = e.values[18];
var ROname = e.values[19];
var ROemail = e.values[20];
var Location = e.values[23];
var subject = "Training Approval Request for " + Course;
var message = "<p >" + "Dear " + ROname + "<p />"
+ Name + " seeks your approval to attend the " + Course + ". The details are as follow:"
+ "<p >" + "<b>Date:</b> " + Start + " - " + End + " <br />"
+ "<b>Time:</b> " + StartTime + " - " + EndTime + " <br />"
+ "<b>Location:</b> " + Location + " <br />"
+ "<b>Course objectives and benefits:</b> " + Details + " <br />"
+ "<b>Course fees:</b> " + "$" + Cost + " <br />" + "<p />"
+ "Please reply directly to this email for your approval or if you have any questions/comments. Thank you. "
MailApp.sendEmail(ROemail, Email, subject, message);
}
After rearranging findCourse as its own function: sorry if I made any mistakes here but i'll try my best to follow all suggestions. If i've added in Logger.log(e) correctly, both functions seem to be undefined
function sendEmail(e) {
Logger.log(e);
var Name = e.values[2];
var Course = findCourse();
var Start = e.values[14];
var End = e.values[15];
var StartTime = e.values[24];
var EndTime = e.values[25];
var Details = e.values[13];
var Cost = e.values[17];
var Email = e.values[18];
var ROname = e.values[19];
var ROemail = e.values[20];
var Location = e.values[23];
var subject = "Training Approval Request for " + Course;
var message = "<p >" + "Dear " + ROname + "<p />"
+ Name + " seeks your approval to attend the " + Course + ". The details are as follow:"
+ "<p >" + "<b>Date:</b> " + Start + " - " + End + " <br />"
+ "<b>Time:</b> " + StartTime + " - " + EndTime + " <br />"
+ "<b>Location:</b> " + Location + " <br />"
+ "<b>Course objectives and benefits:</b> " + Details + " <br />"
+ "<b>Course fees:</b> " + "$" + Cost + " <br />" + "<p />"
+ "Please reply directly to this email for your approval or if you have any questions/comments. Thank you. "
MailApp.sendEmail(ROemail, Email, subject, message);
}
function findCourse (e){
var courseToTake;
//loop through values
for ( var i = 4; i <=12; i ++){
//pull value into variable
var value = e.values[i];
if (value != undefined){
//if we find an actual string value, set the course to take variable
courseToTake = value;
}
}
return courseToTake;
var courseToTake = findCourse(e);
Logger.log(e);
}
I will really deeply appreciate any help or alternative solutions here.
Thank you!
What I changed in your code to address your question:
I assigned the onFormSubmit trigger to your sendEmail function so the event object would no longer be undefined
I added a call to findCourse() so your course variable would no longer be undefined
I fixed the undefined check by changing if(value != undefined) to if(typeof value !== 'undefined')
I added a check for a blank value (This was the important bit in the logic after the faulty undefined check) if(value != '')
Explanation:
To trigger the event, an installable trigger needs to be setup for the On Form Submit event that points to your sendEmail function. This can be found in Resources -> Current Project Triggers
To retrieve the course, you need to call your function findCourse() and pass in the e event object. Example: var course = findCourse(e);. This will assign the return value from findCourse(e); to the course variable. You can then use this variable like normal within the rest of your statements.
When checking for undefined, you need to use typeof and then check for the string of 'undefined', or your check will ironically throw an undefined exception.
The values of the form submit should not be undefined, blank values should just be blank strings. so checking for non-blank strings was necessary to get the course name from the values array.
Fixed Code:
function sendEmail(e) {
Logger.log(e)
var course = findCourse(e);
var Name = e.values[19];
var Start = e.values[12];
var End = e.values[14];
var StartTime = e.values[13];
var EndTime = e.values[15];
var Details = e.values[11];
var Cost = e.values[17];
var Email = e.values[20];
var ROname = e.values[21];
var ROemail = e.values[22];
var Location = e.values[16];
var subject = "Training Approval Request for " + course;
var message = "<p >" + "Dear " + ROname + "<p />"
+ Name + " seeks your approval to attend the " + course + ". The details are as follow:"
+ "<p >" + "<b>Date:</b> " + Start + " - " + End + " <br />"
+ "<b>Time:</b> " + StartTime + " - " + EndTime + " <br />"
+ "<b>Location:</b> " + Location + " <br />"
+ "<b>Course objectives and benefits:</b> " + Details + " <br />"
+ "<b>Course fees:</b> " + "$" + Cost + " <br />" + "<p />"
+ "Please reply directly to this email for your approval or if you have any questions/comments. Thank you. "
MailApp.sendEmail(ROemail, Email+";" + "redactedEmail", subject, message);
}
function findCourse (e){
var courseToTake;
//loop through values
for ( var i = 2; i <=10; i ++){
//pull value into variable
var value = e.values[i];
if (typeof value !== 'undefined'){ //If value is defined
if(value != ''){ //If value is not blank
//if we find an actual non-blank string value, set the course to take variable
courseToTake = value;
}
}
}
return courseToTake;
}
I'm working on trying to trigger an event (to unhide an alert or image) based on gps coordinates falling within a certain range.
I think I need to do something like: If GPS Lat is > x (set based on location I want them to go to) and < y & GPS Long is > z and < a, then show (use js change css to display: block).
Am I down the right path? I'll post what I have as the basics of getting the GPS coordinates to just appear. I'm learning as I go here, so any help is appreciated for the proper structure. Thank you.
document.addEventListener("deviceready", onDeviceReady, false);
var watchID = null;
// device APIs are available
//
function onDeviceReady() {
var options = { timeout: 100000 };
watchID = navigator.geolocation.watchPosition(onSuccess, onError, options);
}
// onSuccess Geolocation
//
function onSuccess(position) {
var element = document.getElementById('geolocation');
element.innerHTML = 'Latitude: ' + position.coords.latitude + '<br />' +
'Longitude: ' + position.coords.longitude + '<br />' +
'<hr />' + element.innerHTML;
}
// onError Callback receives a PositionError object
//
function onError(error) {
alert('code: ' + error.code + '\n' +
'message: ' + error.message + '\n');
}
UPDATE:
I have gotten to the point where I'm not getting errors, now I'm hoping for some help to get a heading based on my current location and the destination. Any help is greatly appreciated. I'm posting my current code below:
document.addEventListener("deviceready", onDeviceReady, false);
var watchID = null;
var gpscoord = null;
var destLat = 37.200401
var destLon = 93.278610
function onDeviceReady() {
var gpsOptions = { timeout: 5000 };
gpscoord = navigator.geolocation.getCurrentPosition(gpsSuccess, gpsError, gpsOptions);
}
//gpsSuccess
//
function gpsSuccess(position) {
var lat = document.getElementById('latitude');
var lon = document.getElementById('longitude');
lat.innerHTML = 'Latitude:' + position.coords.latitude;
lon.innerHTML = 'Longitude:' + position.coords.longitude;
document.getElementById('gotoLat').innerHTML = 'Destination Latitude: ' + destLat;
document.getElementById('gotoLon').innerHTML = 'Destination Longitude: ' + destLon;
}
function gpsError(error) {
alert('code: ' + error.code + '\n' +
'message: ' + error.message + '\n');
}
<div class="container">
<br/>
<br/>
<p id="latitude">Watching latitude...</p>
<p id="longitude">Watching longitude...</p>
<br/>
<p id="gotoLat">Destination latitude...</p>
<p id="gotoLon">Destination longitude...</p>
</div>
Yeah that looks fine. The watcher will call onSuccess when the GPS has been successfully polled, and returns data.
I would save the Longitude and Latitude in the global scope, and then you can perform what ever kind of logic you want on it.