Google App Script - How to use methods without defining their object - javascript

I am writing the script behind a spreadsheet that has lots of durations on it in the format of (##:##.##) (ex 12:43.76). I need to write some code that converts this to just seconds. I wrote code that did the opposite, made seconds into that format. But when writing a custom formula for this, the .split method does not work.
function MTOS(input){
String(input);
if (typeof(input) != "string") {
Logger.log("Not a string")}
var array = input.split(":");
Logger.log('The original string is: "' + input + '"');
var min = Number(array[0]);
var sec = Number(array[1]);
Logger.log("min=" + min);
Logger.log("sec=" + sec);
var MIN = min*60;
Logger.log(MIN);
var ex = MIN+sec;
Logger.log(ex);
return ex;
}
This is what I have in the script editor. The input is the parameter from the spreadsheet when I write the formula in the sheet itself (ex - =MTOS(3:23.53)). When I run the function in the script editor, it gives me the error "TypeError: Cannot call method "split" of undefined. (line 5, file "MTOS")" and in sheets, it returns "Error : Result was not a number." I understand that this is happening because input is not defined in the function itself, so .split cannot work. But how else can I write the custom formula for sheets?
Thank you.

This seems to work for me: (Perhaps I'm misunderstanding the question).
function MTOS(input){
var iA = input.split(":");
var min = Number(iA[0]);
var sec = Number(iA[1]);
Logger.log('Seconds=%s',min * 60 + sec);
}

Related

match() or split() messing up my code

I'm new to programming, I'm learning javascript. I don't understand what's wrong with my code but I'm unable to reach the result (i.e. show the total seconds in the text box). The program works fine until matching the pattern. But it's getting all messed up when I'm using the split() function. Please tell me where I'm going wrong. Thank You
<body>
<script>
function cal() {
var text = document.getElementById("pp").innerHTML;
var pattern = text.match(/[0-2][0-9]:[0-5][0-9]:[0-5][0-9]/);
var b = pattern.split(':');
var seconds = (+b[0]) * 3600 + (+b[1]) * 60 + (+b[2]);
document.getElementById("tot").value = seconds;
}
</script>
<div>
<p id="pp">The Time Right Now Is 12:34:56</p>
Total Seconds: <input type=t ext id="tot"><button onclick="cal()"> Click Here!</button>
</div>
</body>
You can check the console (F12 in Chrome) to see if any errors occur. You can also step through the code to see what's going on by adding a debugger; statement there somewhere.
If you move the JavaScript code to a separate file, you can also write tests (for example with Jasmine) to automate testing your code.
All that being said, the following error is displayed in the console:
Uncaught TypeError: pattern.split is not a function
The fix:
var b = pattern[0].split(':');
But once you've started with a Regex, you can continue that way. The following will group the hours, minutes and seconds
var result = "12:34:56".match(/([0-2][0-9]):([0-5][0-9]):([0-5][0-9])/)
var hours = result[1];
var minutes = result[2];
var seconds = result[3];
Better yet, for date parsing like what you are doing here, you could use a library that offers this sort of things out of the box. MomentJS is a very popular one. If this is the only thing you do, using a library is overkill but if you are doing alot of date parsing/formatting, then it will make things much easier for you.
# Install on command line with npm (you can also use bower, ...)
npm install moment
// import and use
import * as moment from "moment";
var parsed = moment("12:34:56", "HH:mm:ss");
String.prototype.split() is a String method, and String.prototype.match() returns an array.
The problem:
You can not applay .split on the returned value from `.match
Solution:
You need to use array index [0] to match the first element from returned array.
Your code after fixing
function cal() {
var text = document.getElementById("pp").innerHTML;
var pattern = text.match(/[0-2][0-9]:[0-5][0-9]:[0-5][0-9]/);
var b = pattern[0].split(':');
var seconds = (+b[0]) * 3600 + (+b[1]) * 60 + (+b[2]);
document.getElementById("tot").value = seconds;
}
<div>
<p id="pp">The Time Right Now Is 12:34:56</p>
Total Seconds: <input type=t ext id="tot">
<button onclick="cal()"> Click Here!</button>
</div>
Pattern return as list. use conditional statement
<body>
<script>
function cal() {
var text = document.getElementById("pp").innerHTML;
var pattern = text.match(/[0-2][0-9]:[0-5][0-9]:[0-5][0-9]/);
b = pattern[0].split(':');
console.log(b)
var seconds = (b[0]) * 3600 + (b[1]) * 60 + (b[2]);
document.getElementById("tot").value = seconds;
}
</script>
<div>
<p id="pp">The Time Right Now Is 12:34:56</p>
Total Seconds: <input type=t ext id="tot"><button onclick="cal()"> Click Here!</button>
</div>
</body>

Wrong Math Algorithm with javascript?

im trying to make some Algorithm function with javascript and get some problems
function Algorithm() {
var endone;
var endtwo;
var endtheend;
var v1 = document.getElementsByName("v1")[0].value; //worth to 91
var v2 = document.getElementsByName("v2")[0].value; //worth to 61
var v3 = document.getElementsByName("v3")[0].value; //worth to 20
endone = Math.round(v1 * 0.30);
endtwo = Math.round(((v2 + v3) / 2) * 0.70);
endtheend = endone + endtwo;
document.getElementById("ending").innerHTML = "end : " + endtheend;
}
if im doing the same Algorithm with a calculator im getting 55.65 , but when im trying to use this function somehow im getting 2169.
someone might know what is the problem and show me how to solve her?
The problem is that v1, v2 and v3 are not numbers. They are strings. So each calculation you make is relies on implicit conversions and operations between strings.
For instance, in the following snippete we have an implicit conversion of the the string value "91" to a double floating number and then the usual mulitplication is done.
var v1 = "91";
console.log(v1*0.3);
On the other hand below:
var v2 = "61";
var v3 = "20";
console.log((v2 + v3) / 2)
We have a string concatenation "61"+"20" results in a new string "6120" and then "6120" is implicitly converted to a double floating number and the division with 2 is done.
What's the solution ?
You have to parse these values either by using parseInt or parseFloat, like below:
var v2 = "61";
var v3 = "20";
console.log((parseInt(v2,10) + parseInt(v3,10)) / 2)
When you get an HTMLInputElement's value property, what you get is a string.
And the + operator applied to two strings merely concatenates them, so if for instance v2 == "7" and v3 === "0", when you do (v2 + v3), you'll get "70".
The solution to your problem is to simply pass the values through parseInt:
var v1 = parseInt(document.getElementsByName("v1")[0].value, 10);
var v2 = parseInt(document.getElementsByName("v2")[0].value, 10);
var v3 = parseInt(document.getElementsByName("v3")[0].value, 10);
// The second argument to parseInt isn't needed if you only target newer browsers.
I'd suggest you read up on type coercion in JavaScript for more info.
The issue is all of your values (v1, v2, v3) are String type. You need to convert them into Number first. So the following code should work :
function Algorithm() {
var endone;
var endtwo;
var endtheend;
var v1 = Number(document.getElementsByName("v1")[0].value);
var v2 = Number(document.getElementsByName("v2")[0].value);
var v3 = Number(document.getElementsByName("v3")[0].value);
endone = Math.round(v1 * 0.30);
endtwo = Math.round(((v2 + v3) / 2) * 0.70);
endtheend = endone + endtwo;
document.getElementById("ending").innerHTML = "end : " + endtheend;
}
you can also use parseInt if your value contains any alphabetic characters.

A string of form nnnn-nnnn is displayed in a spreadsheet as a date or otherwise incorrectly

I have a script I have been using in my test environment to programmically create a tracking number by parsing the year from timestamp and padding the response index.
function setTrackingNumber(ss, lastRowInx, createDateColumn) //This block generates and stores a tracking number in Column AU on the backend
{
var padTrackNo = "" + lastRowInx;
var trackSize = 4;
var trackingNumberColumn = createDateColumn-3; //trackingNumberColumn is currently in AU (Column 47) Calculating using it's relative position to createDateColumn Position
if (ss.getRange(lastRowInx, trackingNumberColumn).getValue() == "") // so that subsequent edits to Google Form don't overwrite original tracking number
{
if (padTrackNo > trackSize)
{
var padTrackNo = pad(padTrackNo, trackSize);
}
else {} //do nothing
var shortYear = setShortYear(ss, lastRowInx, createDateColumn);
var trackingNumber = shortYear + "-" + padTrackNo;
var createTrackingNumber = ss.getRange(lastRowInx, trackingNumberColumn);
createTrackingNumber.setValue(trackingNumber);
}
else {} //should do nothing
return;
}//This is the end of the setTrackingNumber function
function setShortYear(ss, lastRowInx, createDateColumn)
{
var newCreateDate = ss.getRange(lastRowInx,createDateColumn).getValue();
var strDate = "" + newCreateDate;
var splitDate = strDate.split(" ");
var trimYear = splitDate[3];
var shortYear = trimYear;
return shortYear;
}//This is the end of the shortYear function
function pad(padTrackNo, trackSize)
{
while (padTrackNo.length < trackSize)
{
padTrackNo = "0"+padTrackNo;
}
return padTrackNo;
}//This is the end of pad function
That gets me test result which is as expected ex. 2016-0005. However when we added it to another production sheet it seemed to work with test data and then production data showed up like a date 3/1/2016. production result - first cell.
I thought it must just be formatting the string as a date because of the numbers so I tried formatted the column as plain text but that just changed the date to a plain text version of the date.
I thought this might be similar to needing to specify the format like I did in this question Appending initial timestamp from Google Form to end of record in order to permanently store create date onFormSubmit at #SandyGood 's suggestion so I tried setting the number format as [0000-0000] by changing
createTrackingNumber.setValue(trackingNumber);
to
createTrackingNumber.setValue(trackingNumber).setNumberFormat("0000-0000");
which resulted in the [production result - second cell] which again doesn't match the expected result.
Oddly, some submissions seem to work just fine like [production result - third cell]. Over the past 3 days and approximately 10 records it has been fine, then hinky, then fine, they hinky, then fine again. I am not really sure what else to try to debug this odd behaviour.
Note: I had to parse the date as a string as I was having trouble getting it to parse the date correctly from the create date which is taken from initial timestamp.
To my understanding, "2016-0005" is not a number but a string, so the cell containing it should be formatted as plain text. With a script, this can be done by
range.setNumberFormat('#STRING#')
(source), and this must be done before you set the value to the cell. Like this:
createTrackingNumber.setNumberFormat('#STRING#').setValue(trackingNumber);

How to write arguments in function?

I have been using functions but I am not able to tackle this.
What I have done is created a function, then made this to use the values provided by the document class or ids and do the work. Once work is done then just give the data back! It worked!
Now I want to make this function happen for two divs, the first function works good. The issue is with the second one. The function is correct, their is some other bug while writing the result.
Here is my code:
function time_untilCom(id) {
var Time2 = Date.parse(document.getElementById("time_" + 2).value);
var curTime2 = new Date();
var timeToWrite2 = "";
var seconds2 = Math.floor((curTime2 - Time2) / (1000));
if (seconds2 > 0 && seconds2 < 60) {// seconds..
timeToWrite2 = seconds2 + " seconds ago";
$('#update_' + 2).html(seconds2);
$('#jstime_' + 2).html(timeToWrite2 + " <b>Time that was captured!</b>");
}
}
If I use it as it is, it works! The issue comes when I try to replace these
("time_" + 2), ("#update_" + 2), ("#jstime" + 2) with ("time_" + id), ("#update_" + id), ("#jstime_" + id).
What i want to happen is that the function would be provided with a common ID that is applied throughout the div and use that ID, to get the value of time, convert it to seconds, do other stuff and then provide me with the result in the corresponding element with the id that was in the argument.
function works great, it do provide me with the result. But the issue is with the id its not being sent I guess. Or if is being sent then not being applied. What might be the issue here? And don't mind the seconds i have that covered too.
I am really very sorry for short code:
Pardon me, I was about to write the code for the function too. But electricity ran out!
Here is the code: onload="time_untilCom('2'), this is the way I am executing this.
And once in the main code, it will be executed like this: onload="time_untilCom(#row.Id) because I am using ASP.NET Web Pages I will be using the server side code to write the ID from Database. And will then user the ID throughtout the div to update the time!
From what I understand, you probably want to replace the second line
var Time2 = Date.parse(document.getElementById("time_" + 2).value);
with
var Time2 = Date.parse(document.getElementById(id).value);
And at the end you can also use
$('#'+id).html(timeToWrite2 + " <b>Time that was captured!</b>");
You are passing "id" as an argument, but you never use it inside the function. My question is: In your example you are using 2 as appendix to id attributes. Is it the 2 (or other numbers respectively) that you want to have as the id parameter of the function?
Then you could just replace each + 2 in your code by + id
function time_untilCom(id) {
var Time2 = Date.parse(document.getElementById("time_" + id).value);
var curTime2 = new Date();
var timeToWrite2 = "";
var seconds2 = Math.floor((curTime2 - Time2) / (1000));
if (seconds2 > 0 && seconds2 < 60) {// seconds..
timeToWrite2 = seconds2 + " seconds ago";
$('#update_' + id).html(seconds2);
$('#jstime_' + id).html(timeToWrite2 + " <b>Time that was captured!</b>");
}
}
EDIT: Please tell us where and how exactly do you call time_untilCom? Did you pass the id there?

Addition not working in Javascript

I'm really new to Javascript and trying to create a form where I'm running into some trouble...
When I use + it does not add up to the value, instead it just puts it back to back. Ex: 5+10 (510)
Here's my code if you want to take a look at it. I'd appreciate any help since I can't figure this out on my own.
var service = document.getElementById("service");
var serviceprice = service.options[service.selectedIndex].id;
var tech = document.getElementById("tech");
var techprice = tech.options[tech.selectedIndex].id;
var hours = document.getElementById("hours").value;
// The error happens here
var total = techprice * hours + serviceprice;
I also have an html part which the script gets the data from.
That happens whenever you have a string rather than a number. The + operator performs concatenation for strings. Make sure you parse your strings to numbers using parseFloat or parseInt:
var service = document.getElementById("service");
var serviceprice = parseInt(service.options[service.selectedIndex].id, 10);
var tech = document.getElementById("tech");
var techprice = parseInt(tech.options[tech.selectedIndex].id, 10);
var hours = parseInt(document.getElementById("hours").value, 10);
Note that parseInt takes an argument to specify the base. You almost always want base 10.
Try changing this line:
var total = techprice * hours + serviceprice;
to
var total = techprice * hours + parseFloat(serviceprice);
I suspect 'servicePrice' is a string, and it will then try to concatenate the first value (let's say: 100) with the second value (which is, not a number, but a string, let's say 'test'), the result being '100test'.
Try to convert the string to int first with parseInt or to float with parseFloat
This is not especially elegant, but I find it simple, easy, and useful:
var total = -(-techprice * hours - serviceprice);
or even:
var total = techprice * hours -(-serviceprice);
They both eliminate the ambiguous + operator.

Categories

Resources