Using one javascript function for multiple inputs on one form - javascript

We have a simple age calculating script, that takes a date input (3 selects - day, month, year) and determine how old. It is triggered by an onChange assigned to the year select.
There are several date inputs scattered through the form, each one set up the same, other than the input names (day1 vs day 1 vs day 3, etc).
Currently we have simply duplicated the js code and manually changed the input variables ...
function Age1()
{
var oldDay = document.step1.day1.value;
var oldMonth = document.step1.month1.value;
var oldYear = document.step1.year1.value;
and more script....
function Age2()
{
var oldDay = document.step1.day2.value;
var oldMonth = document.step1.month2.value;
var oldYear = document.step1.year2.value;
and more script....
and so forth.
Ideally we would like to reuse one script, rather than hardcoding one for each instance. I have tried a bunch of ideas to no avail, but the ideal would be to trigger it via: onChange="Age(X);" and then have the js insert the proper variable:
function Age(varX)
{
var oldDay = document.step1.dayX.value;
var oldMonth = document.step1.monthX.value;
var oldYear = document.step1.yearX.value;
and so on ....
Any ideas for us ? Thanks in advance

function Age(varX)
{
var oldDay = document.step1['day' + varX].value;
var oldMonth = document.step1['month' + varX].value;
var oldYear = document.step1['year' + varX].value;
}

Related

google-apps-script cannot read array value ("typeError: "cannot read property "1" ) [duplicate]

This question already has an answer here:
Freezing rows in Sheets with Google Apps throws type error
(1 answer)
Closed 2 years ago.
I'm trying to make my code sending an email by referring to my google sheet data. Im using Apps Script and here is the code. However, as I run my function "sendEmail()", I got "typeError: "cannot read property "1" of undefined(line 17)".
Code line 17
var currentEmail = rows[i][1];
Here is the full code.
var ss = "1kuTkOuCd-wKTS2564oHdxALFbFo-IeyjzToYYhB6NrQ";
var SheetName = "FormResp";
function getRows(){
var rangeName = 'FormResp!A2:E';
var rows = Sheets.Spreadsheets.Values.get(ss, rangeName).values;
return rows;
}
function sendEmails() {
var ss_1 = SpreadsheetApp.openById(ss);
var sheet = ss_1.getSheetByName(SheetName);
var lr = sheet.getLastRow();
for (var i = 0;i<=lr;i++){
rows=getRows();
var currentEmail = rows[i][1];
var startingdate = rows[i][3];
var endingdate = rows[i][4];
MailApp.sendEmail(currentEmail,"Thank You for Applying Leave via Leave form: your request leave starting" + startingdate + "until" + endingdate,"Hello");
}
}
function testgetrow(){
var nama = getRows();
var x = "";
}
I do make a test function "testgetrow()" to check my data, and I do manage to run the function without any error and I do confirm that there is values in my getRows() function.
my getRows() function working, and there is a value in the array as shown in the picture below.
I suppose you can do it any way you wish but this seems a lot simpler to me.
function sendEmails() {
const ss = SpreadsheetApp.openById("1kuTkOuCd-wKTS2564oHdxALFbFo-IeyjzToYYhB6NrQ");
const sh = ss.getSheetByName('FormResp');
const rg = sh.getRange(2,1,sh.getLastRow()-1,5);
const vs=rg.getValues();
vs.forEach(r=>{
var currentEmail = r[1];
var startingdate = r[3];
var endingdate = r[4];
MailApp.sendEmail(currentEmail,"Thank You for Applying Leave via Leave form: your request leave starting" + startingdate + "until" + endingdate,"Hello");
});
}
Answer
The main problem is that you have not declared properly the variable rows in your line 16 rows=getRows(); because you forgot to use the keyword var. Change that line with var rows = getRows() and try it again.
Take a look
You are mixing SpreadsheetApp with Sheets API. I recommend you to pick one and stay there to have a clear and less confusing code.
Try use less functions if they are not really necessary, as #Cooper suggested, you can define the variable rows with getRange that can handle A1 notation ranges and getValues.
Define properly your range in A1 notation: if you write A2:E, your range goes from column A, row 2 until column E, row 1000. You have to add the number of the last row in your range, for example A2:E10.
With the last change, you do not have to calculate the last row, you can simply use rows.length.
It is not necessary to have the id of the spreadsheet if your script is a Container-bound Scripts and not a Standalone Script with getActiveSpreadsheet
I attach you a snippet of the code:
var sheetName = "FormResp";
var spreadsheet_id = "1kuTkOuCd-wKTS2564oHdxALFbFo-IeyjzToYYhB6NrQ";
var ss = SpreadsheetApp.openById(spreadsheet_id).getSheetByName(sheetName)
function sendEmails() {
var rangeName = 'A1:B9';
var rows = ss.getRange(rangeName).getValues()
for (var i = 0; i <= rows.length; i++){
var currentEmail = rows[i][1];
var startingdate = rows[i][3];
var endingdate = rows[i][4];
MailApp.sendEmail(currentEmail,"Thank You for Applying Leave via Leave form: your request leave starting" + startingdate + "until" + endingdate,"Hello");
}
}
I hope that it helps you!
References
SpreadsheetApp
Sheets API
getRange
getValues
getActiveSpreadsheet
Container-bound Scripts
Standalone Script

Jump to current date cell (dates are in one row) Google Sheets

I have a google sheets spreadsheet. Row 2 contains dates e.g. 25/08/2020, 26/08/2020 going across many columns. Is there a script I can run to make it jump to the cell containing the current date when the document is first opened?
I know there is OnOpen() method which you define and it runs on opening the document, however, it is getting the code that actually works that's proving difficult.
Note: I have looked at Google spreadsheet / docs , jump to current date cell on Open but the solutions don't work (I assume due to me having my dates all in one row).
I don't know javascript really well, I understand a little of the basics. Any help would be much appreciated.
Thanks
The code you found at Google spreadsheet / docs , jump to current date cell on Open does not work for you as it only checks the first column.
I modified this code a little to search for dates on a row. Change rowWithDates variable as needed.
function onOpen() { // runs automatically
var rowWithDates = 2; // change as needed
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getActiveSheet();
var range = sh.getDataRange()
var data = range.getValues();
var today = new Date().setHours(0,0,0,0);
var diffref = today;
var diff;
var idx;
for(var n=0;n<range.getWidth();n++){
var date = new Date(data[rowWithDates-1][n]).setHours(0,0,0,0);
diff=today-date;
if(diff==0){break}
Logger.log("diffref = "+diffref+" today-date = diff = "+diff);
if(diff < diffref && diff > 0){idx=n ; diffref=diff}
}
if(n==data.length){n=idx}
n++;
sh.getRange(rowWithDates, n).activate();
}
You can use the code that was provided in the answer you cited in your question, you just need to change a couple of things:
Make it look in a row, rather than a column (note that the data array is changing the second array dimension, rather than the first); and
Make it look in a specific row, rather than just hardcoded to the first (you could just, instead of 0, have the array use a variable "row"; instead, I just had the code pull the data for only the row with dates - this is faster for very large spreadsheets).
function onOpen() {
var row = 8; //set this to be the row with the dates
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getActiveSheet();
var data = sh.getDataRange();
var datesrow = sh.getRange(row,data.getColumn(),row,data.getWidth()).getValues();
var today = new Date().setHours(0,0,0,0);
for(var n=0;n<datesrow[0].length;n++){
var date = new Date(datesrow[0][n]).setHours(0,0,0,0);
if(date==today){break};
}
console.log(n);
n++;
sh.getRange(row,n).activate();
}
Solution:
While the other solutions might work for now, when working with Dates is recommended to consider display values instead. It is also highly recommended to get rid of old for loops and var declarations.
This will be a more futureproof solution:
function onOpen() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sh =ss.getActiveSheet();
const today = new Date();
const today_year= today.getFullYear();
const today_month = addZero(today.getMonth()+1);
const today_day = addZero(today.getDate());
const today_date = today_day.toString() + "/" + today_month.toString() + "/" + today_year.toString();
function addZero(i) {
if (i < 10) {
i = "0" + i;
}
return i;
}
const dates = sh.getRange(2,1,1,sh.getLastColumn()).getDisplayValues().flat(1);
dates.forEach((d,index)=>{
if (d===today_date){
sh.getRange(2,index+1).activate();}});
}
References:
getDisplayValues()

Javascript count two variables goes wrong

I am busy with making a kind of invoice system, where the user can make invoices very easily. Now I am at the point where I have to count up, per product, three different variables/items, but instead of counting them up, my javascript code puts it like text (with the + operator).
Example:
selectmenu 1 = option 0 (where VAT = 8.50 euro's)
selectmenu 2 = option 1 (where VAT = 12.76 euro's)
Now the output has to be (8.50+12.76)= 21.26
The output in my situation is = 8.5012.76
My (partial) javascript code:
$("select#product").on("change", function (e) {
var $row = $(e.target).closest('.productitem');
var selVal = $row.find('#product').val();
var totalvat;
var currentVat = $('#totalvat').val();
var NLhoog = 1.21;
var price0EXC = 40.49;
var price0INC = (price0EXC * NLhoog).toFixed(2);
var price0VAT = (price0INC - price0EXC).toFixed(2);
var price1EXC = 60.74;
var price1INC = (price1EXC * NLhoog).toFixed(2);
var price1VAT = (price1INC - price1EXC).toFixed(2);
if (selVal === "0") {
$row.find("input#vat").val(price0VAT);
$row.find("input#priceEXC").val(price0EXC);
$row.find("input#priceINC").val(price0INC);
totalvat = (currentVat + price0VAT);
$('input#totalvat').val(totalvat);
} else if (selVal === "1") {
$row.find("input#vat").val(price1VAT);
$row.find("input#priceEXC").val(price1EXC);
$row.find("input#priceINC").val(price1INC);
totalvat = currentVat+price1VAT;
$('input#totalvat').val(totalvat);
}
});
I have let the unimportant part of the code away.
If you know what I am doing wrong, please let me know :)
Think this may help?
var currentVat = parseFloat($('#totalvat').val());
You are using var currentVat = $('#totalvat').val(); to get the value from an input I assume? This is a string which will need to be parsed at some to a relevant datatype. When + is used with a string the compiler performs concatenation.
Try something like:
var currentVat = parseFloat($('#totalvat').val());
Or do it later on with:
parseFloat(currentVat);
As you're using numbers as currency I'd consider adding the suffix .ToFixed(2) at the end, and maybe some other formatting

Override existing google calendar event when new event is created via script

I am using a Google Form to schedule appointments based on open events on my Google Calendar. I've sectioned off time slots on the calendar and if the title of the event is "Open", then the time slot can be used to create an event. I would next like to know if it's possible to override and delete the existing open event with the new appointment that is created.
Here is the code I am using to push events to my calendar as they are created in the form:
var calendarID = "";
var startDtID = 5;
var endDtID = 5; // Column containing date/time
var nameID = 2; // Column containing name
var emailID = 3; // Column containing email
var phoneID = 4; // Column containing phone
var formTimeStampID = 1; // column containing timestamp
function getLatestAndSubmitToCalendar() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var lr = rows.getLastRow();
var startDt = sheet.getRange(lr,startDtID,1,1).getValue();
var endDt = sheet.getRange(lr,endDtID,1,1).getValue(); // remove hour and minute for the start/end time
var desc = "Comments :"+sheet.getRange(lr,phoneID,1,1).getValue(); // set comments as description, add in timestamp and submission
var title = sheet.getRange(lr,nameID,1,1).getValue()+" - "+sheet.getRange(lr,emailID,1,1).getValue(); // create title using name and email
createEvent(calendarID,title,startDt,endDt,desc);
}; // run create event function
function createEvent(calendarId,title,startDt,endDt,desc) {
var cal = CalendarApp.getCalendarById(calendarID);
var start = new Date(startDt);
var end = new Date(endDt);
var event = cal.createEvent(title, start, end, {
description : desc
}); // set options for event
};
The CalendarEvent class has a method to delete events through deleteEvent(), but I am confused as to how I can determine the right event to be deleted. How can I match up the date and time of the current event with that of the one that already exists so I can override it?
You'll need to call calendar.getEvents() first, then loop through the event(s) you want to delete, and call .delete() on each of them. Here's the API link: https://developers.google.com/apps-script/reference/calendar/calendar#getEvents%28Date,Date,Object%29
Something like this:
var now = new Date();
var twoHoursFromNow = new Date(now.getTime() + (2 * 60 * 60 * 1000));
var events = CalendarApp.getDefaultCalendar().getEvents(now, twoHoursFromNow,
{search: 'meeting'});
for(int i = 0; i < events.length; i++){
if this is the right event (compare title, times, etc?){
events[i].deleteEvent();
}
}
In this case, you'll probably want to compare the descriptions. Also note that you can pass options to the getEvents call; one you can use to filter during the search is the search parameter like I did above. It filters the returned events on that text.
EDIT: Ideally, you'll want to use this: https://developers.google.com/apps-script/reference/calendar/calendar#getEventSeriesById%28String%29
That gets the event by the ID; I answered with the assumption you didn't have the ID stored anywhere though. If you do, all the better, and you'll be certain you're replacing the right event.
It works! Here is my completed code for adding an event and deleting one that occurs at the same time.
function createEvent(calendarId,title,startDt,endDt,desc) {
var cal = CalendarApp.getCalendarById(calendarID);
var start = new Date(startDt);
var end = new Date(endDt);
var event = cal.createEvent(title, start, end, {
description : desc
});
var events = cal.getEvents(start, end, {
search: 'open'
});
for (i in events){
events[i].deleteEvent();
}
};

Find Index of Column(s) after it has been Moved

We are using DHTMLX Grid. Need some help, please.
I have a table and each columns (has filter/dropdown) are allocated an id eg. fac, date, sel, loc, tag ... etc
We have hard coded the index of columns to set and get the cookie elsewhere.
function doInitGrid(){
mygrid.setColumnIds("fac,date,sel,loc,tag"); //set ids
mygrid.attachEvent("onFilterStart",function(ind,data)
{
setCookie("Tray_fac_filter",mygrid.getFilterElement(0).value,365); //column index 0
setCookie("Tray_loc_filter",mygrid.getFilterElement(3).value,365);//column index 3
setCookie("Tray_tag_filter",mygrid.getFilterElement(4).value,365); //column index 4
mygrid.getFilterElement(0).value = getCookie("Tray_fac_filter")
mygrid.getFilterElement(3).value = getCookie("Tray_dep_filter")
mygrid.getFilterElement(4).value = getCookie("Tray_prg_filter")
});
}
But when the columns are moved, the problem arises as the index of the column changes yet it is set in setCookie /getCoookie
DHTMLX allows to get the index of the id using --
var colInd = grid.getColIndexById(id);
eg: var colInd = grid.getColIndexById(date); // outputs 1.
After moving the date column to the end -- fac, sel, loc, tag, date // it will output 4.
However, we have about 14 columns that can be moved/rearranged and I could use the
var colInd = grid.getColIndexById(id); 15 times
var facInd = grid.getColIndexById("fac");
var dateInd = grid.getColIndexById("date");
var selInd = grid.getColIndexById("sel");
var locInd = grid.getColIndexById("loc";
var tagInd = grid.getColIndexById("tag");
and put those variables in the set/get cookie. I was thinking if there was a better way.
To understand the code better, I have put the minimised version of the code in fiddle.
http://jsfiddle.net/19eggs/s5myW/2/
You've got the best answer I think. Do it in a loop and it's easier:
var cookie_prefix = "Fray_filter_";
var cookie_dur = 365;
var num_cols = dhx_grid.getColumnCount();
// filter vals to cookies
for (var col_idx=0; col_idx<num_cols; col_idx++) {
var filter = mygrid.getFilterElement(col_idx)
if (filter) { // not all columns may have a filter
var col_id = dhx_grid.getColumnId(col_idx);
var cookie_name = cookie_prefix+col_id;
setCookie(cookie_name, filter.value, cookie_dur);
}
}
// cookies to filter vals
for (var col_idx=0; col_idx<num_cols; col_idx++) {
var col_id = dhx_grid.getColumnId(col_idx);
var filter_val = getCookie(cookie_prefix+col_id);
var filter = mygrid.getFilterElement(col_idx)
filter.value = filter_val;
}
You can use dhtmlxgrid native event to assign the correct id everytime a column is moved.
The event is called onAfterCMove, you can check the documentation here. onAfterCMove Event
You would do something like:
mygrid.attachEvent('onAfterCMove',function(cInd,posInd){
//Your processing here to change the cookies; where cInd is the index of the column moved
//and posInd, is the position where it Was moved
}):

Categories

Resources