Increment of global variable in google app script isn't working - javascript

How to increment my global variable 'currentstep' in Google App Script. The third if statement, I used currentstep++ but it doesn't increase as it stayed at 2. Furthermore, I had tried currentstep += 1; and currentstep = currentstep + 1; Both methods don't work as well.
function check_command(data){
var text = data.message.text;
if(text == "/start" || text == "/start"){
currentstep = 1;
return;
}
if (text == "/survey" || text == "/survey"){
currentstep = 2;
return;
}
if (text){
currentstep++;
}
return;
}

In google apps script every time you make a function call the global variable get reinitialized. So typically it's better to use PropertiesService or CacheService for global parameters that you wish to change from one execution to another.

The conditions like this:
if (text == "/start" || text == "/start") { ... }
Have little sense. They are equal with this:
if (text == "/start") { ... }
So your function can be boiled down to this:
function check_command(data) {
var text = data.message.text;
if (text == "/start") { currentstep = 1; return }
if (text == "/survey") { currentstep = 2; return }
if (text) { currentstep++ }
}
And it works fine by itself, as far as I can tell.
Here is a test:
function check_command(data) {
var text = data.message.text;
if (text == "/start") { currentstep = 1; return }
if (text == "/survey") { currentstep = 2; return }
if (text) { currentstep++ }
}
var currentstep = 0;
var data = {message: {text: ""}};
var texts = [
,
"",
false,
"/start",
"/survey",
"",
,
"aaa",
"/survey",
123,
"/start",
""
]
for (let txt of texts) {
data.message.text = txt;
check_command(data);
console.log("currentstep = " + currentstep + " for '" + txt + "'");
}
Probably #Cooper is right. You're doing something fancy that we can't know from your question. Are you running the script several times and trying to keep the global value between the runs?
Update
If you suspect that the problem is a global variable you can modify your function to avoid using the global variable within the function:
function check_command(data, counter) {
var text = data.message.text;
if (text == "/start") return = 1;
if (text == "/survey") return = 2;
if (text) counter++;
return counter;
}
And call the function this way:
currentstep = check_command(data, currentstep);

Related

How does one prevent NaN as return value of various number value calculations?

Im new to Javascript and im trying to do a calculation which changes depending on the number that is typed into the input.
However the functions make the output into a NaN, so Im wondering if I can transform the NaN in a normal number(So that I can add hUeCalc and massCalc together and display it as a number) to use or if I have to use another option to do the calculations.
Maybe switch and case might be an option but im not quite sure if they would have the effect I need.
In the Code below you can see the function which is executed when pressed on a button. Right now when I click the button that activates the function calc I get NaN in tax.innerHTML instead of a number.
Thanks in advance.
function calc() {
let hubraum = Number(hubraumComponent.value);
let emission = Number(emissionComponent.value);
let masse = Number(masseComponent.value);
let hUeCalc = Number(function (){
if (Diesel.checked == true) {
((Math.ceil((hubraum/100)))*9.5)+((emission-95)*2);
}
else if (Benzin.checked == true) {
((Math.ceil((hubraum/100)))*2)+((emission-95)*2);
};
});
let masseCalc = Number(function (){
let masseValue;
if (masse <= 2000) {
masseValue = (Math.ceil((masse/200)*5.625));
}
else if (masse >= 3000) {
masseValue =(Math.ceil((masse/200)*6.01));
}
else if (masse >= 3500) {
masseValue = (Math.ceil(masse/200)*6.39);
};
});
// let masseValue = (Math.ceil (masse/200));
let berechnung = (hUeCalc + masseCalc);
tax.innerHTML = (berechnung) + "€";
console.log('Calc has been done');
console.log('hubraum value is ' + hubraum);
console.log('emission value is ' + emission);
console.log('masse value is ' + masse);
console.log('hubraumcalc value is ' + hUeCalc);
console.log('massecalc value is ' + masseCalc);
}
Also here is the HTML incase you want to see the button that activates all of this
<div class="input-field-second-calc" onclick="calc()">
<input type="button" class="btn btn-outline-primary" value="berechnen">
<br>
<a id="tax"></a>
</div>
You need to return a value in your two functions !
When you do :
let hUeCalc = Number(function (){
if (Diesel.checked == true) {
((Math.ceil((hubraum/100)))*9.5)+((emission-95)*2);
}
else if (Benzin.checked == true) {
((Math.ceil((hubraum/100)))*2)+((emission-95)*2);
};
})
You're basically saying please convert the return value of the function to a number and assign it to hUeCalc. But as the function return nothing. It is trying to convert undefined to a number. which give NaN as a result.
The same goes for :
let masseCalc = Number(function (){
let masseValue;
if (masse <= 2000) {
masseValue = (Math.ceil((masse/200)*5.625));
}
else if (masse >= 3000) {
masseValue =(Math.ceil((masse/200)*6.01));
}
else if (masse >= 3500) {
masseValue = (Math.ceil(masse/200)*6.39);
};
});
By the way, with :
if (masse <= 2000) {
masseValue = (Math.ceil((masse/200)*5.625));
}
else if (masse >= 3000) {
masseValue =(Math.ceil((masse/200)*6.01));
}
else if (masse >= 3500) {
masseValue = (Math.ceil(masse/200)*6.39);
};
You'll never get to the last else if as if we try it with 3700 for example. It will not match on the first if but on the second as 3700 is greater than 3000. You need to invert the order of the two else if.
And you need to add a else too for the number between 2000 and 3000 (If it's a accepted value)
A code refactoring should separate both current calculations each into a part that provides/implements a single specialized calculation function and a part which invokes the calculation with the correct values including valid fallback values in case some conditions could not be met.
In addition I suggest to fix the naming. Don't mix the languages. Skip the German part since most of the code (including the logging) is named and commented in English.
function getCalculatedHUeValue(displacement, emission, fuelFactor) {
return (Math.ceil(displacement / 100) * fuelFactor) + ((emission - 95) * 2);
}
function getCalculatedMassValue(mass, massFactor) {
return Math.ceil(mass / 200 * massFactor);
}
function calc() {
const displacement = Number(displacementComponent.value);
const emission = Number(emissionComponent.value);
const mass = Number(massComponent.value);
const hUeCalc = getCalculatedHUeValue(displacement, emission,
(Diesel.checked && 9.5) ||
(Benzin.checked && 2) ||
0 // default/fallback value needs to be provided/known.
);
const massCalc = getCalculatedMassValue(mass,
((mass <= 2000) && 5.625) ||
((mass >= 3500) && 6.39) ||
((mass >= 3000) && 6.01) ||
// what is the factor for the uncovered
// mass range in between 2001 and 2999?
0 // this fallback value has to be provided/known.
);
const result = (hUeCalc + massCalc);
tax.innerHTML = (result + "€");
console.log('Calculation is done');
console.log('displacement value is ' + displacement);
console.log('emission value is ' + emission);
console.log('mass value is ' + mass);
console.log('hUeCalc value is ' + hUeCalc);
console.log('massCalc value is ' + massCalc);
}
If you try the following code I think it should work. As you see if you want to use a function to assing a value the function has to return something, if it doesn't there's no value to assign. You also need to make sure the function is excecuted, if you don't the let hUeCalc = function(){} just becomes the function identifier.
function calc() {
let hubraum = Number(hubraumComponent.value);
let emission = Number(emissionComponent.value);
let masse = Number(masseComponent.value);
let hUeCalc = Number(function (){
if (Diesel.checked == true) {
return ((Math.ceil((hubraum/100)))*9.5)+((emission-95)*2);
}
else if (Benzin.checked == true) {
return ((Math.ceil((hubraum/100)))*2)+((emission-95)*2);
};
}());
let masseCalc = Number(function (){
let masseValue;
if (masse <= 2000) {
return masseValue = (Math.ceil((masse/200)*5.625));
}
else if (masse >= 3000) {
return masseValue =(Math.ceil((masse/200)*6.01));
}
else if (masse >= 3500) {
return masseValue = (Math.ceil(masse/200)*6.39);
};
}()); // using () right after the function makes it so it get excecuted immediately
// let masseValue = (Math.ceil (masse/200));
let berechnung = (hUeCalc + masseCalc);
tax.innerHTML = (berechnung) + "€";
console.log('Calc has been done');
console.log('hubraum value is ' + hubraum);
console.log('emission value is ' + emission);
console.log('masse value is ' + masse);
console.log('hubraumcalc value is ' + hUeCalc);
console.log('massecalc value is ' + masseCalc);
}

How to register/unregister events in a dynamic way, using Vanilla JS

I've spoken to my teacher and he told me that the reason why you would place the <script> element as last part of <body>, use onload= event directly on HTML-element, or in another way include the script in <body> (or deferring its execution), is because you want to guarantee that the script will only be activated once the DOM has been loaded, and the needed elements can be accessed. But... this is not the convention since it will be very difficult to scale in a solution where multiple HTML-documents are involved, sharing the same file resources such as JavaScript in this case. Instead, you'll handle this flow of execution by registering events properly using JS.
I've been told to put the Window Event load at the end my of JS file.
These are the error I get in booking.html: Uncaught TypeError: Cannot read property 'target' of undefined at addEvent (main.js:65) at start (main.js:10) addEvent.
Why do I get this error?
Here is my code:
function start() {
let path = window.location.pathname;
if (path.endsWith("contact.html")) {
browserDetection;
} else if (path.endsWith("employees.html") || path.endsWith("ourfleet.html")) {
registerGalleryEvents();
} else if (path.endsWith("booking.html")) {
addEvent();
getSeat();
}
/* browser detector */
var browserDetection = (function (agent) {
switch (true) {
case agent.indexOf("edge") > -1:
return "MS Edge (EdgeHtml)";
case agent.indexOf("edg") > -1:
return "Microsoft Edge";
case agent.indexOf("opr") > -1 && !!window.opr:
return "Opera";
case agent.indexOf("chrome") > -1 && !!window.chrome:
return "Chrome";
case agent.indexOf("trident") > -1:
return "Internet Explorer";
case agent.indexOf("firefox") > -1:
return "Mozilla Firefox";
case agent.indexOf("safari") > -1:
return "Safari";
default:
return "other";
}
})(window.navigator.userAgent.toLowerCase());
document.getElementById("specific-h3").innerHTML = "Here you can contact us if you have any questions. <br>\ <br>\ And by the way, you are using " + browserDetection + " browser.";
function registerGalleryEvents() {
const galleryImgs = document.querySelectorAll(".galleryImg");
galleryImgs.forEach((galleryImg) => {
galleryImg.addEventListener("click", () => {
displayImage(galleryImg);
});
});
}
//declaring the displayImage function. reference: https://stackoverflow.com/a/65974064/14502646
function displayImage(thumbnail) {
const currentImgSrc = thumbnail.getAttribute("src");
const [imgName, ext] = currentImgSrc.split(".");
document.getElementById('myPicture').src = imgName + '-big.' + ext;
}
var seats = document.getElementsByClassName('grid-item')
// Saving Javascript objects in sessionsStorage.
var data = JSON.parse(sessionStorage.getItem('bookingData'))
function addEvent(event) {
//Makes sure that the first 6 seats are Business class and the rest are Economy.
if (parseInt(event.target.innerHTML) >= 1 && parseInt(event.target.innerHTML) <= 6) {
document.getElementById('classType').innerHTML = 'Class Type: Business'
} else {
document.getElementById('classType').innerHTML = 'Class Type: Economy'
}
//event.target.innerHTML is the number of seat that is selected.
document.getElementById('seat').innerHTML = 'Seat Selected: ' + event.target.innerHTML
document.getElementById('seatNumber').value = event.target.innerHTML
var selectedSeats = document.getElementsByClassName("selected");
if (selectedSeats.length > 0) {
for (var j = 0; j < selectedSeats.length; j++) {
selectedSeats.item(j).className = selectedSeats.item(j).className.replace('grid-item selected', 'grid-item');
}
}
event.target.className = event.target.className + " selected";
}
for (var i = 0; i < seats.length; i++) {
seats[i].addEventListener('click', addEvent)
}
var seatList = document.getElementsByClassName("grid-item")
for (var i = 0; i < data.length; i++) {
seatList.item(parseInt(data[i].seatNo) - 1).removeEventListener("click", addEvent)
seatList.item(parseInt(data[i].seatNo) - 1).className = seatList.item(parseInt(data[i].seatNo) - 1).className.replace('grid-item', 'grid-item booked')
}
document.getElementsByClassName('reset').addEventListener('click', function () {
location.reload()
})
function getSeat() {
var inp = document.getElementsByClassName("grid-item selected");
if (inp.length > 0) {
var inputData = {
firstName: document.getElementById('fname').value,
lastName: document.getElementById('lname').value,
identityNo: document.getElementById('identity').value,
classType: document.getElementById('classType').innerHTML,
seatNo: parseInt(document.getElementById('seatNumber').value)
}
if (JSON.parse(sessionStorage.getItem('bookingData')) != null) {
var bookingData = JSON.parse(sessionStorage.getItem('bookingData'))
bookingData.push(inputData)
sessionStorage.setItem('bookingData', JSON.stringify(bookingData))
} else {
console.log('block')
var bookingData = []
bookingData.push(inputData)
sessionStorage.setItem('bookingData', JSON.stringify(bookingData))
}
alert('Flight booked successfully.')
window.print()
} else {
alert("Select a seat before proceeding!")
}
}
}
window.addEventListener("load", start);

How do you increment the value of a variable based on a substring in Javascript?

I'm trying to create a script where I validate a phone number without too much regex in my scripts. So far I have:
var phone = document.PizzaForm.phone.value;
var num = [1,2,3,4,5,6,7,8,9,0];
var delim = ["(" , ")" , "-" , "."];
var incr = 0;
var status = 0;
if (document.PizzaForm.phone.value.substring() = num) {
incr++;
return;
}
if (incr < 10) {
var statustext=1;
alert("Phone data is missing.");
}
if (document.PizzaForm.phone.value.substring[0,4,8] != num || document.PizzaForm.phone.value.substring[0,4,8] != delim) {
(status var statustext=1;
alert("Phone data is incorrect.");)
}
if (statustext == 0) {
return true;
}
else {
return false;
}
}
but it's not working. I'm trying to increment my incr everytime there is a number so if incr < 10, i get a message that there aren't enough numbers. Anyone see where I might be going wrong?
In your below if condition :
if (document.PizzaForm.phone.value.substring[0,4,8] != num || document.PizzaForm.phone.value.substring[0,4,8] != delim) {
(status var statustext=1;
alert("Phone data is incorrect.");)
}
Declare your statustext set globally. Not inside the if condition.
status set to 1 directly.
change your logic as below
var statustext = 0;
if (document.PizzaForm.phone.value.substring[0,4,8] != num || document.PizzaForm.phone.value.substring[0,4,8] != delim) {
status = 1;
statustext = 1;
alert("Phone data is incorrect.");)
}

Ensuring that an entered name doesn’t end with a space

I am trying to get it so that if I type in a name that ends with a space, the textfield will go red. Most of the code works its just one method does not seem to be working.
The issue must be somewhere in the last index part?
var NamePass = true;
function ValidateName() {
var BlankPass = true;
var GreaterThan6Pass = true;
var FirstBlankPass = true;
var BlankMiddleName = true;
if (document.getElementById('Name').value == "") {
BlankPass = false;
}
var Size = document.getElementById('Name').value.length;
console.log("Size = " + Size);
if (Size < 7) {
GreaterThan6Pass = false;
}
if (document.getElementById('Name').value.substring(0, 1) == " ") {
FirstBlankPass = false;
}
var LastIndex = document.getElementById('Name').value.lastIndexOf();
if (document.getElementById('Name').value.substring((LastIndex - 1), 1) == " ") {
FirstBlankPass = false;
}
string = document.getElementById('Name').value;
chars = string.split(' ');
if (chars.length > 1) {} else
BlankMiddleName = false;
if (BlankPass == false || GreaterThan6Pass == false || FirstBlankPass == false || BlankMiddleName == false) {
console.log("BlankPass = " + BlankPass);
console.log("GreaterThan6Pass = " + GreaterThan6Pass);
console.log("FirstBlankPass = " + FirstBlankPass);
console.log("BlankMiddleName = " + BlankMiddleName);
NamePass = false;
document.getElementById('Name').style.background = "red";
} else {
document.getElementById('Name').style.background = "white";
}
}
http://jsfiddle.net/UTtxA/10/
lastIndexOf gets the last index of a character, not the last index in a string. I think you meant to use length instead:
var lastIndex = document.getElementById('Name').value.length;
Another problem with that, though, is that substring takes a start and end index, not a start index and a substring length. You could use substr instead, but charAt is easier:
if (document.getElementById('Name').value.charAt(lastIndex - 1) == " ") {
FirstBlankPass = false;
}
Now, for some general code improvement. Instead of starting with all your variables at true and conditionally setting them to false, just set them to the condition:
var NamePass = true;
function ValidateName() {
var value = document.getElementById('Name').value;
var BlankPass = value == "";
var GreaterThan6Pass = value.length > 6;
var FirstBlankPass = value.charAt(0) == " ";
var LastBlankPass = value.charAt(value.length - 1) == " ";
var BlankMiddleName = value.split(" ").length <= 1;
if (BlankPass || GreaterThan6Pass || FirstBlankPass || LastBlankPass || BlankMiddleName) {
console.log("BlankPass = " + BlankPass);
console.log("GreaterThan6Pass = " + GreaterThan6Pass);
console.log("FirstBlankPass = " + FirstBlankPass);
console.log("BlankMiddleName = " + BlankMiddleName);
NamePass = false;
document.getElementById('Name').style.background = "red";
} else {
document.getElementById('Name').style.background = "white";
}
}
A couple more points of note:
It’s probably a good idea to use camelCase variable names instead of PascalCase ones, the latter usually being reserved for constructors
blah == false should really be written as !blah
An empty if followed by an else can also be replaced with if (!someCondition)
That function looks like it should return true or false, not set the global variable NamePass
Penultimately, you can sum this all up in one regular expression, but if you intend to provide more specific error messages to the user based on what’s actually wrong, then I wouldn’t do that.
function validateName() {
return /^(?=.{6})(\S+(\s|$)){2,}$/.test(document.getElementById('name').value);
}
And finally — please keep in mind that not everyone has a middle name, or even a name longer than 6 characters, as #poke points out.

Next/Previous button throws error

I keep getting the following error when I try to insert values by clicking the Next button on values that are already entered in.
Unable to get the value of the property '0': object is null or undefined.
I believe the error is happening at the last value in the array. I indicated the line below with a comment in the code. I want it to get the next value in the array but there isn't one created yet (it gets the next value just fine if the next value is not the last one in the array).
I think that is the reason it's throwing an object null. However, I can't seem to check for the null/undefined and set it using statements such as result[count+1][0] == undefined because it doesn't work! It always throws an error no matter what I do.
Some help would be much appreciated.
Test case:
Insert a value in text box 1 and text box 2
Click Next
Click Previous (in order to edit the values inserted above)
Change the values in the text boxes to something else
Click Next -- error happens
Code:
<html>
<head>
<script type="text/javascript"></script>
</head>
<body>
<script type="text/javascript">
var result = new Array();
var count = 0;
var input1 = new Array();
var input2 = new Array();
function move(direction) {
if(direction == 'next')
{
var rate1 = [document.getElementById("txt1").value];
var rate2 = [document.getElementById("txt2").value];
if (result.length == count){
if (rate1 == '' || rate2 == '') {
alert('you need to put in a value');
}
else {
result.push([[rate1], [rate2]]);
document.getElementById("txt1").value = '';
document.getElementById("txt2").value = '';
count++;
}
}
else {
try{
(result[count][0]) = document.getElementById("txt1").value;
(result[count][1]) = document.getElementById("txt2").value;
document.getElementById("txt1").value = result[count++][0]; //error happening here. trying to show next value but there isn't one created yet.
document.getElementById("txt2").value = result[count++][1];
document.getElementById("txt1").value = '';
document.getElementById("txt2").value = '';
}
catch(err) {
alert(err.description);
}
count++;
}
}
if (direction == 'prev')
{
if(count <= 0)
{
alert("no more elements");
}
else
{
var prev_val1 = (result[count - 1][0]);
document.getElementById("txt1").value = prev_val1;
var prev_val2 = (result[count - 1][1]);
document.getElementById("txt2").value = prev_val2;
count--;
}
}
document.getElementById("txtresult").value = result;
}
</script>
<li>text 1</li>
<input type="text" id="txt1"/>
<br>
<li>text 2</li>
<input type="text" id="txt2"/>
<br>
<input type="button" id="btn" value="next" onclick="move('next')" />
<input type="button" id="btnprevious" value="previous" onclick="move('prev')" />
<br>
<input type="text" id="txtresult"/>
</body>
</html>
You can add a check like this:
if (typeof result[count++] === "undefined") { /* do or do not */ };
Right before:
document.getElementById("txt1").value = result[count++][0];
function move(direction) {
if(direction == 'next')
{
var rate1 = [document.getElementById("txt1").value];
var rate2 = [document.getElementById("txt2").value];
if (result.length == count){
if (rate1 == '' || rate2 == '') {
alert('you need to put in a value');
}
else {
result.push([[rate1], [rate2]]);
document.getElementById("txt1").value = '';
document.getElementById("txt2").value = '';
count++;
}
}
else {
try{
(result[count][0]) = document.getElementById("txt1").value;
(result[count][1]) = document.getElementById("txt2").value;
if( result[ ++count ] ) // this checks for undefined
{
document.getElementById("txt1").value = result[count][0]; //error happening here. trying to show next value but there isn't one created yet.
document.getElementById("txt2").value = result[count][1];
}
else
{
document.getElementById("txt1").value = '';
document.getElementById("txt2").value = '';
count--; // decrement counter
}
}catch(err) {
alert(err.description);
}
count++;
}
}
if (direction == 'prev')
{
if(count <= 0)
{
alert("no more elements");
}
else
{
var prev_val1 = (result[count - 1][0]);
document.getElementById("txt1").value = prev_val1;
var prev_val2 = (result[count - 1][1]);
document.getElementById("txt2").value = prev_val2;
count--;
}
}
document.getElementById("txtresult").value = result;
}
why do you do count++ in these 2 lines?
document.getElementById("txt1").value = result[count++][0]; //error happening here. trying to show next value but there isn't one created yet.
document.getElementById("txt2").value = result[count++][1];
seems like interpreter first increment the count and then try to get item of result which is undefined...
as i undestand pressing previous must "set cursor" to previous vaues so you can change previously entered values... in this case you shouldn't increment counter in these lines.. just remove ++
I don't get why you embedded the arrays three deep. I cleaned up some of the code and made the names more understandable (at least to me).
Regardless, when you were on the last value in the array, count++ didn't exist. Also, don't use count++ as this will increment your count var. Don't use ++ to simplify unless you truly know what you're doing and want to increment. Also, tricky shortcuts will confuse people trying to read your code, so try to be as explicit as possible. (There are exceptions to this statement, as in, you don't need to write for a person who has never coded before)
Here is working javascript:
var result = new Array();
var count = 0;
function move(direction) {
if(direction == 'next') {
var box1 = document.getElementById("txt1").value; //why did you wrap these as arrays?
var box2 = document.getElementById("txt2").value; //
if (result.length == count){
if (box1 == '' || box2 == '') {
alert('you need to put in a value');
} else {
result.push([box1, box2]); //why did you wrap individual numbers in arrays?
document.getElementById("txt1").value = '';
document.getElementById("txt2").value = '';
}
} else {
try{
result[count][0] = document.getElementById("txt1").value;
result[count][1] = document.getElementById("txt2").value;
if(result[count+1]) { // need this because if on last value in the array, count+1 will not exist yet
document.getElementById("txt1").value = result[count+1][0]; //do not do ++. this will increment count here. don't be tricky with ++
document.getElementById("txt2").value = result[count+1][1]; //because it will confuse others and lead to off by 1 errors
} else {
document.getElementById("txt1").value = '';
document.getElementById("txt2").value = '';
}
}
catch(err) {
alert(err.description);
}
}
count++;
}
if (direction == 'prev') {
if(count <= 0){
alert("no more elements");
} else {
var prev_val1 = result[count - 1][0];
var prev_val2 = result[count - 1][1];
document.getElementById("txt1").value = prev_val1;
document.getElementById("txt2").value = prev_val2;
count--;
}
}
document.getElementById("txtresult").value = result;
}

Categories