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

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);

Related

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

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);

Minification leads to redeclaration error in FF and IE

We encountered a problem with the minification provided by the NuGet package Microsoft.AspNet.Web.Optimization, as it seems to have problems with let. Somehow the minifier sets the name of the variables bookingDefaultIndex and i to the same name (i). This makes Firefox and IE 11 report a scope problem (Firefox reports SyntaxError: redeclaration of let i, IE 11 reports Let/Const redeclaration), because the variable was already defined. Without minification, the code works just fine in IE and FF. Chrome reports no problems with the minified code.
In the following code snippets, I marked the relevant lines with a comment that starts with // [SO-COMMENT], so you can search for that to see the problematic lines.
This is the unminified function that causes problems:
_handleDDLValuesByContext: function () {
if (this.options.isCreate) {
if (this.options.isChildCreation) {
//If we are creating a child ->
this.$ddlBookingType.val(this.options.data.BookingTypeID);
this.$ddlAllocationUnit.val(this.options.data.AllocationUnitID);
this.$ddlEffortAllocationUnit.val(this.options.data.AllocationUnitID);
if (this.options.data.ServiceCategoryID == null) {
this.$ddlServiceCategory.val('-1').trigger('change');
if (this.options.data.PricePerUnit != null) {
this.$structureRate.val(GetFormat(this.options.data.PricePerUnit));
}
} else {
this.$ddlServiceCategory.val(this.options.data.ServiceCategoryID).trigger('change');
}
//If we are creating a child, prefill his accounting type with the parent accounting type
if (this.options.data.AccountingTypeID == null) {
this.$ddlAccountingType.val('-1').trigger('change');
} else {
this.$ddlAccountingType.val(this.options.data.AccountingTypeID).trigger('change');
}
} else {
//If it's parent creation ->
let bookingTypes = this.options.structureSpecificData.BookingTypes;
let bookingDefaultID = null;
// [SO-COMMENT] the following variable is minified to 'i'
let bookingDefaultIndex = null;
for (let i = 0, len = bookingTypes.length; i < len; i++) {
if (bookingTypes[i].IsDefault) {
bookingDefaultID = bookingTypes[i].ID;
bookingDefaultIndex = i;
}
}
let allocationTypes = this.options.structureSpecificData.AllocationUnitTypes;
if (bookingDefaultID == null) {
//In case there's no default booking type id, we set the booking types, allocations and effort allocations to their first available value
this.$ddlBookingType.val(bookingTypes[0].ID);
this.$ddlAllocationUnit.val(allocationTypes[0].ID);
this.$ddlEffortAllocationUnit.val(allocationTypes[0].ID);
} else {
let allocationDefaultID = null;
this.$ddlBookingType.val(bookingDefaultID).trigger('change');
allocationTypes = [];
let bookings = this.options.structureSpecificData.BookingTypes;
let allocations = this.options.structureSpecificData.AllocationUnitTypes;
// [SO-COMMENT] this is the 'original' i
for (let i = 0, len = allocations.length; i < len; i++) {
if (allocations[i].BaseUnitID == bookings[bookingDefaultIndex].BaseUnitID) {
allocationTypes.push(allocations[i]);
}
}
for (let i = 0, len = allocationTypes.length; i < len; i++) {
if (allocationTypes[i].IsDefault) {
allocationDefaultID = allocationTypes[i].ID;
}
}
if (allocationDefaultID == null) {
this.$ddlAllocationUnit.val(allocationTypes[0].ID);
this.$ddlEffortAllocationUnit.val(allocationTypes[0].ID);
} else {
this.$ddlAllocationUnit.val(allocationDefaultID);
this.$ddlEffortAllocationUnit.val(allocationDefaultID);
}
}
this.$ddlServiceCategory.val('-1');
}
} else {
//If we are edditing ->
this.$ddlBookingType.val(this.options.data.BookingTypeID);
this.$ddlAllocationUnit.val(this.options.data.AllocationUnitID);
this.$ddlEffortAllocationUnit.val(this.options.data.AllocationUnitID);
if (this.options.data.IsParentElement) {
this.$ddlServiceCategory.val('-1').trigger('change');
//We have to check against a NaN type since the effort and the total cost can be of that type
//in case we have a structure hierarchy with an accounting type of fixed price and therefore no effort and cost
if (isNaN(this.options.structureTotalCost)) {
this.$structureTotalCost.val('');
} else {
this.$structureTotalCost.val(GetFormat(this.options.structureTotalCost));
}
if (isNaN(this.options.structureEffort)) {
this.$structureEffortUnits.val('');
} else {
this.$structureEffortUnits.val(GetFormat(this.options.structureEffort));
}
} else {
if (this.options.data.ServiceCategoryID == null) {
this.$ddlServiceCategory.val('-1').trigger('change');
if (this.options.data.PricePerUnit != null) {
this.$structureRate.val(GetFormat(this.options.data.PricePerUnit));
this._checkTotalCostCalculation();
}
} else {
if (this.options.data.PricePerUnit !== null) {
this.$structureRate.val(GetFormat(this.options.data.PricePerUnit));
this.$ddlServiceCategory.val(this.options.data.ServiceCategoryID);
this._checkTotalCostCalculation();
} else {
this.$ddlServiceCategory.val(this.options.data.ServiceCategoryID).trigger('change');
}
}
}
//Since we are editing we should prefill the accounting type with the accounting id and the fixed price too if it exists
//And not trigger anything
if (this.options.data.AccountingTypeID == null) {
this.$ddlAccountingType.val('-1').trigger('change');
} else {
this.$ddlAccountingType.val(this.options.data.AccountingTypeID).trigger('change');
}
if (isNaN(this.options.totalFixedPrice)) {
this.$fixedPrice.val('');
} else {
this.$fixedPrice.val(GetFormat(this.options.totalFixedPrice));
}
}
}
And this is the minified version:
_handleDDLValuesByContext: function() {
if (this.options.isCreate)
if (this.options.isChildCreation) this.$ddlBookingType.val(this.options.data.BookingTypeID), this.$ddlAllocationUnit.val(this.options.data.AllocationUnitID), this.$ddlEffortAllocationUnit.val(this.options.data.AllocationUnitID), this.options.data.ServiceCategoryID == null ? (this.$ddlServiceCategory.val("-1").trigger("change"), this.options.data.PricePerUnit != null && this.$structureRate.val(GetFormat(this.options.data.PricePerUnit))) : this.$ddlServiceCategory.val(this.options.data.ServiceCategoryID).trigger("change"), this.options.data.AccountingTypeID == null ? this.$ddlAccountingType.val("-1").trigger("change") : this.$ddlAccountingType.val(this.options.data.AccountingTypeID).trigger("change");
else {
let t = this.options.structureSpecificData.BookingTypes,
i = null, // [SO-COMMENT] this shouldn't be named i
r = null;
for (let n = 0, u = t.length; n < u; n++) t[n].IsDefault && (i = t[n].ID, r = n);
let n = this.options.structureSpecificData.AllocationUnitTypes;
if (i == null) this.$ddlBookingType.val(t[0].ID), this.$ddlAllocationUnit.val(n[0].ID), this.$ddlEffortAllocationUnit.val(n[0].ID);
else {
let t = null;
this.$ddlBookingType.val(i).trigger("change");
n = [];
let f = this.options.structureSpecificData.BookingTypes,
u = this.options.structureSpecificData.AllocationUnitTypes;
for (let t = 0, i = u.length; t < i; t++) u[t].BaseUnitID == f[r].BaseUnitID && n.push(u[t]);
// [SO-COMMENT] here there is a second i that causes the problem
for (let i = 0, r = n.length; i < r; i++) n[i].IsDefault && (t = n[i].ID);
t == null ? (this.$ddlAllocationUnit.val(n[0].ID), this.$ddlEffortAllocationUnit.val(n[0].ID)) : (this.$ddlAllocationUnit.val(t), this.$ddlEffortAllocationUnit.val(t))
}
this.$ddlServiceCategory.val("-1")
} else this.$ddlBookingType.val(this.options.data.BookingTypeID), this.$ddlAllocationUnit.val(this.options.data.AllocationUnitID), this.$ddlEffortAllocationUnit.val(this.options.data.AllocationUnitID), this.options.data.IsParentElement ? (this.$ddlServiceCategory.val("-1").trigger("change"), isNaN(this.options.structureTotalCost) ? this.$structureTotalCost.val("") : this.$structureTotalCost.val(GetFormat(this.options.structureTotalCost)), isNaN(this.options.structureEffort) ? this.$structureEffortUnits.val("") : this.$structureEffortUnits.val(GetFormat(this.options.structureEffort))) : this.options.data.ServiceCategoryID == null ? (this.$ddlServiceCategory.val("-1").trigger("change"), this.options.data.PricePerUnit != null && (this.$structureRate.val(GetFormat(this.options.data.PricePerUnit)), this._checkTotalCostCalculation())) : this.options.data.PricePerUnit !== null ? (this.$structureRate.val(GetFormat(this.options.data.PricePerUnit)), this.$ddlServiceCategory.val(this.options.data.ServiceCategoryID), this._checkTotalCostCalculation()) : this.$ddlServiceCategory.val(this.options.data.ServiceCategoryID).trigger("change"), this.options.data.AccountingTypeID == null ? this.$ddlAccountingType.val("-1").trigger("change") : this.$ddlAccountingType.val(this.options.data.AccountingTypeID).trigger("change"), isNaN(this.options.totalFixedPrice) ? this.$fixedPrice.val("") : this.$fixedPrice.val(GetFormat(this.options.totalFixedPrice))
}
My google searches for IIS minification scope problems didn't show any useful results. What could we try to investigate and fix this problem, other than not to use let?

How to do some thing to all class on js

every body.
I try to make function as each function on jquery i make this code
var $ = function (e){
var d = document
if(e){
if ("#" == e.substring(0, 1)) {
return d.querySelectorAll(e);
} else if ("." == e.substring(0, 1)) {
return d.querySelectorAll(e);
} else if ("." != e.substring(0, 1) && "#" != e.substring(0, 1)){
return d.querySelectorAll(e)
}
}
}
i want it if i write $(".example").style.background = "red";
If you want create each function, this code is work
function each(a,b) {
var c = document.querySelectorAll(a);
for(var i = c.length - 1; i >= 0; i--) {
return b.call(i, c[i]);
}
}
//use
each(".class", function(e) {
e.style.background = "red";
});
You need selector engine like sizzle if you want write $(".class").style.background = "red";

what is wrong with .this. javascript if else code?

it works if i use the first half only but i need to widen the parameters
//document.querySelectorAll('font[color="black"]');
var fonts = document.querySelectorAll('font[color="black"]');
var searchString = 'Mir';
var searchString2 = 'MirrorCreator';
for (var i = 0; i < fonts.length; i++) {
var font = fonts[i];
if (fonts[i].innerHTML.indexOf(searchString) !== - 1) {
//alert('Match');
var eventLink = 'ComeHere';
var elA = document.createElement('a');
elA.setAttribute('id', eventLink);
elA.setAttribute('name', eventLink);
font.appendChild(elA);
window.location.hash = 'ComeHere';
break;
}
else (fonts[i].innerHTML.indexOf(searchString2) !== - 1) {
//alert('Match');
var eventLink2 = 'ComeHere2';
var elA2 = document.createElement('a');
elA2.setAttribute('id', eventLink2);
elA2.setAttribute('name', eventLink2);
font.appendChild(elA2);
window.location.hash = 'ComeHere2';
break;
}
}
Here you have wrong syntax:
else (fonts[i].innerHTML.indexOf(searchString2) !== - 1) {
It should be simple
else {
or
else if (fonts[i].innerHTML.indexOf(searchString2) !== - 1) {
You need to change your if else statement.
if(// conditional)
{
// do something.
}
else if(// conditional){
// do something....
}
Your else needs to be else if, because else isn't expecting (fonts[i].innerHTML.indexOf(searchString2) !== - 1)

Trying to add and remove items from an array

The script works by asking user for add or remove an item in the array. Then asks to continue this loop. The problem here is that my script doesn't seem to match my user's input (removeItem) to the item in the list (myList[i]). I'm at a lost as to why this is failing to match.
// new method for removing specific items from a list
Array.prototype.remove = function(from,to) {
var rest = this.slice((to || from) + 1 || this.length);
this.length = from < 0 ? this.length + from : from;
return this.push.apply(this, rest);
};
printList = function() {
var listLength = myList.length;
for (i = 0; i < listLength; i++) {
document.write(i + ":");
document.write(myList[i] + "<br/>");
};
document.write("<br/><br/>");
};
// initial list
var myList = new Array ();
if (myList.length === 0) {
document.write("I have " + myList.length + " item in my list. It is: <br/>");
}
else {
document.write("I have " + myList.length + " items in my list. They are: <br/>");
}
printList();
var continueAdding = "yes";
var askToContinue = "";
while (continueAdding === "yes") {
// loop
var askUser = prompt("What do you want to [A]dd or [R]emove an item to your inventory?").toUpperCase();
switch (askUser) {
case "A": { // add an user specified item to the list
var addItem = prompt("Add something to the list");
myList.push(addItem);
printList();
break;
}
case "R": { // remove an user specified item from the list
var removeItem = prompt("what do you want to remove?");
var listLength = myList.length;
for (i = 0; i < listLength; i++) {
if (removeItem === myList[i]) {
document.write("I found your " + removeItem + " and removed it.<br/>");
myList.remove(i);
}
else {
document.write(removeItem + " does not exist in this list.<br/>");
break;
}
if (myList.length === 0) {
myList[0] = "Nada";
}
};
printList();
break;
}
default: {
document.write("That is not a proper choice.");
}
};
askToContinue = prompt("Do you wish to continue? [Y]es or [N]o?").toUpperCase(); // ask to continue
if (askToContinue === "Y") {
continueAdding = "yes";
}
else {
continueAdding = "no";
}
}
Your loop never allows it to loop through all the items, because it breaks on the first iteration if the item doesn't match.
The break statement should be in the if block, not in the else block - use this instead:
for (i = 0; i < listLength; i++) {
if (removeItem === myList[i]) {
document.write("I found your " + removeItem + " and removed it.<br/>");
myList.remove(i);
break;
}
else {
document.write(removeItem + " does not exist in this list.<br/>");
}
};
if (myList.length === 0) {
myList[0] = "Nada";
}
Also, note that it's looking for an exact match, case sensitive, same punctuation, and everything. If you want it to be a little more lenient you'll need to modify the script to convert both strings to lowercase and strip punctuation before comparing them.
Edit: Just noticed something else -- testing for an empty list needs to be done outside the loop. I updated the above code to reflect this.

Categories