I have a search box helping users navigate the rooms at school via this link. Trying to search for user-based input, whereas if there is anything user entered that matches the query Selector based on class + text content within an SVG rect element (room number text or school class name) is taking a user to a certain floor + highlights the room. The part I'm struggling with is as follows in this floors.js file:
function searchCabinet() {
let userInput = document.getElementById("search").value;
let isCabinetFound = false;
if (document.querySelectorAll('.rooms').textContent.includes(userInput)) {
isCabinetFound = true;
selectFloor('.rooms', userInput);
}
I have assigned the class .rooms to divs found in SVG floor files.
Floor0 as an example. Also, have floor1.svg, floor2.svg and floor3.svg
Should the above be put into for loop?
The previous version had getElementbyID, but that would search for the exact room name specified in Map array. So if I entered room 157. with a dot after a number, that would return 0 results. Since the room planner is going to have class names too, like 5.a room 157. Searching by .textContent or .innerText would make more sense.
The final idea is to get it to run like this example. The drawback with this, again, is that if the user enters 157. with a dot it fails to search. Since it only searches by unique ID. While what's needed is searching by any text that is within the container box (room number, class number, might be even room volume in the future).
I have two ideas. But first add the room names and the numbers as classes like class="name-lab num-1". With that no need to filter elements.
const floorCount = 4
var selectedFloor = 0
function nextOrSelectFloor(select = null) {
if (select != null) {
//Iterate by one but if it's last element set to zero
if (selectedFloor == floorCount - 1) selectedFloor = 0
else selectedFloor += 1
} else selectedFloor = select
document.getElementById("floor-map").setAttribute("data", `img/floor${selectedFloor}.svg`)
}
var selectedCabIndex = 0
let matchedRooms = []
function searchCabinet() {
//Clean the list before new search
selectedCabIndex = 0
matchedRooms = []
let userInput = document.getElementById("search").value;
//We will search each floor once
const floorSearchLimit = floors.length
for (let i = 0; i < floorSearchLimit; i++) {
document.querySelectorAll(
`[class*='name-${userInput}'],
[class*='num-${userInput}']`
).forEach(e => matchedRooms.push({
cab: e, //Push the cab and the floor number to select
floor: i
}))
nextOrSelectFloor()
}
if (matchedRooms.length > 0) selectNextCab()
else {
//Cab not found
document.getElementById('alert').classList.remove("hide");
document.getElementById('alert').classList.add("show");
document.getElementById('alert').classList.add("showAlert");
setTimeout(function () {
closeAlert();
}, 5000);
}
}
//Add button to page and set onclick
function selectNextCab() {
const previousSlectedCab = matchedRooms[selectedCabIndex - 1]
previousSlectedCab.cab.classList.remove("highlight")
//This function runs after search and should start from zero, so first highlight then increase index
const selectedCab = matchedRooms[selectedCabIndex]
nextOrSelectFloor(selectedCab.floor)
selectedCab.cab.classList.add("highlight")
selectedCabIndex += 1
}
You can define the next page with a variable. If don't go to next page add all SVG files to page and give display:none to them with a class. This would be more suitable. That's your decision
Related
For context, just starting with JS, and wanted to do something simple, create a Higher/Lower guessing game. I have it fully working, though I wanted to add some more color to it, so my idea is to create a list of previously guessed numbers and whether that number is higher or lower than the target number (the number that they have to guess). though I currently have it set up where
const guesses = document.querySelector(".guesses");
and
guesses.textContent += userGuess + ' ';
so it just creates this extremely long, sentence-like line of previously guessed numbers that is in all white. Is there any way for me to change it so that each individual guess can somehow be listed and can be either red or green depending on if the target number is higher or lower?
For the if, else, and else if statements, I just have it so that it shows a certain text stating if the guess is too high or too low, and if it's exact, then it gives the option to restart the game
Edit, more parts of the code:
js:
let userGuess = guessField.valueAsNumber
const guessField = document.getElementById('guessField');
guessField is just an input tag in HTML
then in js, I have it generate some number, save that as randomNumber with let randomNumber = Math.floor(Math.random() * 100 + 1)
then if userGuess === randomNumber then show a p tag saying that it's right, and give it a green background or else say it's wrong (that p tag). Then I have it look if the userGuess number is lower or higher than the target number (aka the randomNumber) if it's too high, show a paragraph saying it's too high, and if it's too low, show a paragraph saying it's too low.
Add guesses in a list instead of just as text in a div. Add backgroundColor style to the result p tag to show whether guess is higher or lower or correct.
let randomNumber = Math.floor(Math.random() * 10 + 1)
const guesses = document.querySelector("#guesses");
const result = document.querySelector("#result");
function checkNum() {
let guessField = document.getElementById('guessField');
let userGuess = parseInt(guessField.valueAsNumber, 10);
var node = document.createElement("li");
var textnode = document.createTextNode(userGuess);
node.appendChild(textnode);
guesses.appendChild(node);
guessField.value = "";
result.style.backgroundColor = "tomato";
if (userGuess === randomNumber) {
result.style.backgroundColor = "aquamarine";
result.innerHTML = "You are right";
} else if (userGuess < randomNumber) {
result.innerHTML = "Guess is lower";
} else {
result.innerHTML = "Guess is higher";
}
}
p {
font-weight: bold;
}
<ul id="guesses">
</ul>
<input type="number" id="guessField" />
<button onclick="checkNum()">check</button>
<p id="result"></p>
We have very minimal info here on what you would like to accomplish and the code you are using however I think we'll be able to help you out here :)
there are a few approaches you can take here, I'm not sure if you're using any databases for your use case but since you're starting off I'm going to assume you simply want to store the values submitted via the input field in an array and later iterate through the array in an effort to pull values from it and perform operations with each iteration.
first you would need to declare an array:
const guessedNumbers = [];
next to store the values from user input you would need to to create a submit event listener on your form that will invoke a function to store the value user submits in the guessedNumbers array. In order to store the values in the guessedNumbers array you can use the .push method:
form = document.querySelector('your-form-selector');
form.addEventListener('submit', (e) => {
const userInputValue = document.querySelector('your-input-field-selector').value;
guessedNumbers.push(userInputValue);
});
Now if you need to access the values stored in the guessedNumbers array, there are multiple built in methods that allow you to accomplish this. Have a look at this MDN link that will shed some light on these array methods. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
for example you may want to iterate through each value in the array and console.log each iteration's value:
guessedNumbers.forEach((number) => console.log(number))
Happy coding!
I have Implemented a treeview that allows a user to drag and drop a node from one tree to another. The user can also reorder the node they just dropped to some other location in the tree as well as duplicate and remove existing nodes.
What I want to do next is so that every time a node is added or duplicated, it adds an incremented number to the end of the text if the text with that number doesn't exists.
Take this treeview for example.
Hello
Hello (2)
World (2)
World
Test
If I were to add a child node containing the text World to the node with the text Test, this is how the treeview should look like then.
Hello
Hello (2)
World (2)
World
Test
World (3)
If I were to remove the node containing the text World, and add a node containing the text World. The treeview should look like this.
Hello
Hello (2)
World (2)
Test
World (3)
World
Note that it didn't add an incremented number because it found that the text World didn't exist.
Right now I simply have an object containing the text as its key and storing the number of times it has encounter that text. Every time a node is added or duplicated, it increments the number of times it has seen that text.
The harder part is that when a node gets removed and the user adds a node with the same text, I need to somehow calculate which nodes got removed, update the dictionary appropriately and add the next unique number to each node.
Note - Only a single node can be added at a time but when it comes to duplicating or removing a node, not only is the node in question duplicated or removed but also its children. So you can imagine that when a node gets duplicated and the node has children, the algorithm that calculate the next unique number has to run not only for the node but also its children.
My question is, what data structure or technique can I employ to accomplish this?
I like this question. I’ll try to come back with code samples when I’m not on mobile.
You could go crazy with data structures trying to pre-compute the numeric value that should be assigned to the next inserted node, but like you pointed out, you’d have to remember to update when items were removed.
The DOM is already a tree. You have access to a node’s parent and children through parentNode and childNodes respectively.
I suspect that, for most cases, recursively searching the tree for the lowest number you can append will be faster than maintaining a list. The logic could be something like this:
given a node, some target text, and the current number
if the node contains the target text,
and the node contains the current number (or no number if the current number is 0),
increment the number
if the node has children,
for each child,
recurse using the child node, search text, and current number
return the current number
Passing in the root node, the search text, and 0 would recursively search the tree and return the lowest number still available.
If the number returned was 0 then either no matching nodes were found or all the matching nodes had a number (the original node with no number was deleted) and we are safe to insert a numberless node.
If a number greater than 0 was returned, then we are guaranteed that it is the lowest number we can use since, if it already existed in a matching node, it would have been incremented.
This approach also has the advantage of eliminating the work required when removing a node. Even if gaps are left in the numbers used for each match, the recursive function above will find the lowest gap and plug it. Once the gap is filled, it will increment to the next available gap or back to a number larger than all the numbers currently in use.
The last case is when a node is copied. What I would do is use another recursive function to incrementally clone the copied tree into the destination node’s children. Each node that was added would use the same addNode function used to insert a new node, and would therefore use the same recursive function above to assign a number.
The assumption this approach makes is that we are okay to number cloned nodes in the order in which we encounter them. If this is not acceptable and they must stay in the order in which the source subtree’s nodes were numbered, you have some additional work to do before insertion.
Here is solution that I was able to come up with. The solution has as its time complexity O(N) and space complexity O(1) (Not sure about the latter)
First I created a number array containing all the counts found so far.
const counts: number[] = [];
First, we need a recursive function that accepts as a callback the node that it has currently traverse. In that callback, we will search for the target text and if it is found, we will parse the text, calculate the sorted index using binary search and then push the value at that specific index.
// Assumes that there are only one set of parenthesis. Adjust this function for
// your use case.
const extractNumberFromParenthesis = (text: string): number => {
const start = text.indexOf('(');
const end = text.indexOf(')');
const number = text.substr(start + 1, end - start - 1);
// The value 1 in this case represents the target text with no parenthesis
return number ? parseInt(number) : 1;
}
const getSortedIndex = (value: number): number => {
let low = 0;
let high = counts.length;
while (low < high) {
// Prevent overflow and use bitwise operator for small performance gains.
const mid = low + ((high - low) >> 1);
if (counts[mid] < value) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
};
// Recurse through the whole tree starting from the root node.
this._tree.recurseDown((node) => {
if (!node.text.includes(text)) {
return;
}
const count = extractCountFromParenthesis(node.text);
const index = getSortedIndex(count);
counts.splice(index, 0, count);
});
Finally we can calculate the next unique number by searching for the first occurrence where counts[i] !== i + 1
const getNextUniqueCount = () => {
let nextUniqueCount = 0;
while (
nextUniqueCount < counts.length &&
counts[nextUniqueCount] === nextUniqueCount + 1
) {
nextUniqueCount += 1;
}
return nextUniqueCount;
};
Here is the whole code for reference.
getTextWithNextUniqueCount(text: string): string {
const counts: number[] = [];
const extractCountFromParenthesis = (text: string): number => {
const start = text.indexOf("(");
const end = text.indexOf(")");
const count = text.substr(start + 1, end - start - 1);
return count ? parseInt(count) : 1;
};
const getSortedIndex = (value: number): number => {
let low = 0;
let high = counts.length;
while (low < high) {
const mid = low + ((high - low) >> 1);
if (counts[mid] < value) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
};
this._tree.recurseDown((node) => {
if (!node.text.includes(text)) {
return;
}
const count = extractCountFromParenthesis(node.text);
const index = getSortedIndex(count);
counts.splice(index, 0, count);
});
const getNextUniqueCount = (): number => {
let nextUniqueCount = 0;
while (
nextUniqueCount < counts.length &&
counts[nextUniqueCount] === nextUniqueCount + 1
) {
nextUniqueCount += 1;
}
return nextUniqueCount;
};
const addCountToText = (): string => {
const count = getNextUniqueCount();
return count > 0 ? `${text} (${count + 1})` : text;
};
return addCountToText();
}
This entire code will run each time we add a new node or duplicate it. No need to call this function when the node is removed.
I have a quick links widget with different types of links/menus that the user can choose from. Only four different menu options can be shown at the same time - not more or less.
In code I first extract all the menu options which come in the form in [1,2,3...] which corresponds to the rows in a list where the menu options is stored.
The user chooses menu options is also returned in the same way with an array like [2,3,8,9] with the number corresponding which row to get from the list.
Example:
All menu/widgets
Travel
Hotel
Car
Buss
Airplane
Holiday
This will return an array [1,2,3,4,5,6]
And if I choose to save hotel, buss, airplane and holiday then my user settings will return [2,4,5,6].
Problem:
It works, until a widget is deleted from the list that the user has saved then the widget only will show three menus/links. I want the widget to always show four links, so if one is missing I need to populate the array. So if its missing, I want to show another link. It would be good, but not needed, to take a link that is set to default when its missing (always the first four in the list). I have set up a logic for that but its not working.
Code:
public async getUserWidgets(): Promise<Widget[]> {
return new Promise<Widget[]>(async(resolve, error) => {
let allWidgets = await this.getAllWidgets(); // Returns an array of all links [1,2,4...]
let userRepository = new UserProfileRepository(this.absoluteWebUrl);
let userSettings = await userRepository.getUserExtensionValues(this.context); //contains the user saved widgets ex [2,3,6,7]
var result:Widget[] = [];
// if the user has no settings, or less than 4 saved links
if (userSettings == null || userSettings.QuickLinksWidgets == null || userSettings.QuickLinksWidgets.length < 4) {
result = allWidgets.filter((w) => {return w.defaultWidget;}).slice(0,4); //default widget but not really needed.
}
else {
var ids = userSettings.QuickLinksWidgets;
for (let i = 0; i < 4; i++) {
let id = '' + ids[i];
let w = allWidgets.filter((e) => { return e.id == id;});
if (w.length == 0) {
continue;
}
result.push(w[0]);
}
};
resolve(result);
}); }
From what you described, it sounds like maybe you're not updating properly (calling getUserWidgets when userSettings.QuickLinksWidgets changes? First check to make sure it's called as you expect.
If getUserWidgets is being called properly, try to add defaults to their settings until you have 4 links total. Right now you are using default links if they have any less than 4 in their settings.
For example:
// take up to 4 user links and make sure we don't exceed the length of the array
for (let i = 0; i < 4 && i < userSettings.QuickLinksWidgets.length - 1; i++) {
// get the id of the widget in the user's settings
let widgetId = userSettings.QuickLinksWidgets[i].id
// find the widget with a matching id and add it to our results
result.push(allWidgets.find(w => w.id === widgetId)
}
// if there's not already 4 links, add more to our list
let j = 0
while (result.length < 4) {
// check the first 4 user links to make sure we didn't include this link already
if (!userSettings.QuickLinksWidgets.slice(0, 4).includes(allWidgets[j].id)) {
// add the new widget to the results
result.push(allWidgets[j])
}
j++
}
resolve(result)
Update: The difference is I'm not trying to make one list I'm trying to make a button that can be clicked and generate a random name
Goal: Click a button and randomly generate a name from an array. I'm trying to be able to click the button and show one name randomly at a time with no repeating names. So far I've been able to randomly select a name but the names still repeat. How could I change my code to avoid any repeating names?
$( ".next").click(function() {
$(".intro").hide()
var people = ["Andrew", "Adam", "Seth", "Mattos", "Eric"];
for(i=0;i<1;i++){
var randomPosition = Math.floor(Math.random() * people.length);
var selected = people.splice(randomPosition,1);
console.log(selected)
$('#person').text(selected)
if ($('#person').text() === "Mattos"){
$("#selectedPerson").text("Mattos")
}
if ($('#person').text() === "Andrew"){
$("#selectedPerson").text("Andrew")
}
if ($('#person').text() === "Eric"){
$("#selectedPerson").text("Eric")
}
if ($('#person').text() === "Seth"){
$("#selectedPerson").text("Seth")
}
if ($('#person').text() === "Adam"){
$("#selectedPerson").text("Adam")
}
}
});
The problem is that you're creating the array every time you enter the function. So splicing the name out of the array has no effect, because you'll refill it the next time. You need to move the array initialization out of the function.
Other issues: splice() returns an array, not a single element, even if you're only splicing out 1 element from the array. You don't need a for() loop if you're only looping 1 time. All the if statements were unneeded, since you're just assigning the same strings in all cases.
And you should check for the case where you've run out of names.
var people = ["Andrew", "Adam", "Seth", "Mattos", "Eric"];
$( ".next").click(function() {
$(".intro").hide();
if (people.length == 0) { // No names left to show
return;
}
var randomPosition = Math.floor(Math.random() * people.length);
var selected = people[randomPosition];
people.splice(randomPosition,1);
console.log(selected)
$('#person,#selectedPerson').text(selected);
});
When I check the boxes in the HTML file, it doesn't account for more than one being checked. How to I make it add the total of every box that is clicked, not just one?
for (i = 0; i < g_radSize.length; i++) {
if (g_chkExtras[i].checked === true) {
g_sExtras += g_chkExtras[i].value + ", ";
g_fTotal += gc_fExtrasPrice;
}
}
Full Code
// DO NOT DELETE ANYTHING IN THIS FILE
/*jsl:option explicit*/
/*jsl:declare $*//*jsl:declare addEventListener*//*jsl:declare isDigits*//*jsl:declare alert*//*jsl:declare blur*//*jsl:declare clearInterval*//*jsl:declare clearTimeout*//*jsl:declare close*//*jsl:declare closed*//*jsl:declare confirm*//*jsl:declare console*//*jsl:declare Debug*//*jsl:declare defaultStatus*//*jsl:declare document*//*jsl:declare event*//*jsl:declare focus*//*jsl:declare frames*//*jsl:declare getComputedStyle*//*jsl:declare history*//*jsl:declare Image*//*jsl:declare length*//*jsl:declare location*//*jsl:declare moveBy*//*jsl:declare moveTo*//*jsl:declare navigator*//*jsl:declare open*//*jsl:declare opener*//*jsl:declare opera*//*jsl:declare Option*//*jsl:declare parent*//*jsl:declare Number*//*jsl:declare parseInt*//*jsl:declare print*//*jsl:declare prompt*//*jsl:declare resizeBy*//*jsl:declare resizeTo*//*jsl:declare screen*//*jsl:declare scroll*//*jsl:declare scrollBy*//*jsl:declare scrollTo*//*jsl:declare setInterval*//*jsl:declare setTimeout*//*jsl:declare status*//*jsl:declare top*//*jsl:declare window*//*jsl:declare XMLHttpRequest*/
// Constants (Constants are variables that never change throughout the running of your program. They are almost always declared globally.)
var gc_fSandwichPrice = 5.99; // Price for each sandwich (Version 1 and 2 only)
var gc_fExtrasPrice = 1.50; // Price for each extra item
// GLOBAL VARS
// Global object vars
var g_divErrors;
var g_radSandwich;
var g_radSize;
var g_chkExtras;
// Other global vars
var g_fTotal;
var g_sSandwich;
var g_sSize;
var g_sExtras;
// DO IT: Hook up an event handler for window.onload to the Init function.
window.onload = Init;
function Init() {
// DO IT: Change the version number in the line below, if necessary, so it accurately reflects this particular version of Dirty Deli.
document.getElementById("h1Title").innerHTML = "Dirty Deli 1.0";
// DO IT: grab and assign any html objects you need to work with
g_divErrors = document.getElementById("divErrors");
g_radSandwich = document.getElementsByName("radSandwich");
g_radSize = document.getElementsByName("radSize");
g_chkExtras = document.getElementsByName("chkExtras");
// DO IT: Set the innerHTML of spanExtrasPrice to gc_fExtrasPrice. Tip: Use the .toFixed() method to display it with 2 decimal places
document.getElementById("spanExtrasPrice").innerHTML = gc_fExtrasPrice.toFixed(2);
// DO IT: Hook up any event handlers you need
document.getElementById("btnCalculateTotal").onclick = CalculateTotal;
document.getElementById("btnProcessOrder").onclick = ProcessOrder;
// Version 2
// DO IT: You need to hook up an event handler that runs whenever the user selects a different Payment option.
//This is the "onchange" event. I suggest you use an anonymous function, and make use of the *selectedIndex* property to see if they chose the credit card.
//This function will check to see if the user selected the Credit card option. If they did, set the CSS visibility property to "visible", otherwise set it to "hidden".
document.getElementById("selPayment").onchange =
function() {
var divCreditCardInfo = document.getElementById ("divCreditCardInfo");
if (document.getElementById("selPayment").selectedIndex === 2) {
divCreditCardInfo.style.visibility = "visible";
}
else {
divCreditCardInfo.style.visibility = "hidden";
}
};
} // function Init()
// function Init
function CalculateTotal() {
// this function should be called when the user clicks the Calculate Total button. Its purpose is mainly to, well, calculate the total. Remember to hook up an appropriate event handler so this function will be called when they click.
// DO IT: clear out divErrors (set the innerHTML to an empty string)
g_divErrors.innerHTML = "";
// DO IT: Tip: you're going to be adding to g_fTotal. Remember: adding anything to garbage will always give you garbage. So how do you prevent this error?
// Same deal for g_sExtras.
g_fTotal = 0;
g_sExtras = " ";
/* DO IT:
Sandwich code - Version 1
Using an IF statement, see which radio button they checked, and assign the value of the selected sandwich to a global var name g_sSandwich.
If nothing is selected, set divErrors to "Select a sandwich", and exit the function.
Sandwich code - Version 2
Within each IF statement remove the line of code you wrote for Version 1.
Replace it with a call to a function (that you will write) named GetSandwichName().
When you call this function, pass it one parameter - the index of the radSandwich radio button that the user checked.
More info on the function itself is given below.
*/
/* if (g_radSandwich[0].checked === true) {
GetSandwichName(0);
}
else if (g_radSandwich[1].checked === true) {
GetSandwichName(1);
}
else if (g_radSandwich[2].checked === true) {
GetSandwichName(2);
}
else if (g_radSandwich[3].checked === true) {
GetSandwichName(3);
}
else {
g_divErrors.innerHTML = "Select a sandwich";
return;
}
*/
// Version 3
/* CONVERT: Sandwich code
Using a FOR loop and a single IF statement within the loop, see which radio button they checked.
When you find it, set g_sSandwich to the sandwich name
and break out of the loop using the break command.
If nothing is selected, set divErrors to "Select a sandwich", and exit the function.
But how do you know if nothing was selected? Use a boolean variable in the If statement,
then check its value after you get out of the loop.
Remember: Your code should be flexible enough so that if the number
of sandwiches change, your code can still work.
Afterall, that's one of the reasons we're using a loop.
Do NOT call the GetSandwichName() function. Incorporate its code here, and remove it.
*/
var iChecked = false;
var i;
for (i = 0; i < g_radSandwich.length; i++) {
if (g_radSandwich[i].checked) {
iChecked = true;
g_sSandwich = g_radSandwich[i].value;
break;
}
}
if (iChecked === false) {
g_divErrors.innerHTML = "Select a sandwich";
return;
}
// Version 1
/* DO IT:
This is the Size code.
Make sure they selected a size.
Update the total by adding the price of a sandwich (which is already declared as a constant) to the total
If nothing is selected, set divErrors to "Please choose a size", and exit the function.
Tip: An If Statement is the key here.
*/
// Version 2
/*
In this version, the sandwiches are not all the same price.
The price of each sandwich is contained within the title attribute of the radSandwich radio button for that sandwich
(take a look at the html to verify this).
So, modify the IF statement from Version 1. You need to call a function (that you will write) named GetSizeUpdateTotal(). More on that below.
*/
/*
if (g_radSize[0].checked === true) {
GetSizeUpdateTotal(0);
}
else if (g_radSize[1].checked === true) {
GetSizeUpdateTotal(1);
}
else if (g_radSize[2].checked === true) {
GetSizeUpdateTotal(2);
}
else {
g_divErrors.innerHTML = "Please choose a size";
return;
}
*/
// Version 3
/* CONVERT: Size code
Once again, using a FOR loop and a single IF statement within the loop,
see which radio button they checked, get the price and update the total just like you did previously.
Then break out of the loop using the break command.
If nothing is selected, set divErrors to "Please choose a size", and exit the function.
Do NOT call the GetSizeUpdateTotal() function. Incorporate its code here, and remove it.
*/
iChecked = false;
var price;
for (i = 0; i < g_radSize.length; i++) {
if (g_radSize[i].checked) {
iChecked = true;
price = g_radSize[i].title;
price = price.substr(1);
price += Number(price);
g_sSize = g_radSize[i].value;
g_fTotal += price;
break;
}
}
if (iChecked === false) {
g_divErrors.innerHTML = "Please choose a size";
return;
}
/* DO IT:
"Extras" code - Version 1
Using an IF statement, see which extra(s) they checked. For each extra selected, do the following:
Concatenate the value of the selected extra to a global var name g_sExtras.
Update the Total with the price of the Extra.
"Extras" code - Version 2
Remove each IF statement you wrote for Version 1. Replace it with a call to a function (that you will write) named GetExtraUpdateTotal().
When you call this function, pass it one parameter - the index of the chkExtras checkbox that the user checked.
More info on the function itself is given below.
*/
/*
GetExtraUpdateTotal(0);
GetExtraUpdateTotal(1);
GetExtraUpdateTotal(2); */
// Version 3
/* CONVERT: "Extras" code
Again, using a FOR loop and a single IF statement within the loop, do what needs to be done.
Remember NOT to break out of the loop when you find a checked checkbox (there may be more).
Do NOT call the GetExtraUpdateTotal() function. Incorporate its code here, and remove it.
*/
for (i = 0; i < g_radSize.length; i++) {
if (g_chkExtras[i].checked === true) {
g_sExtras += g_chkExtras[i].value + ", ";
g_fTotal += gc_fExtrasPrice;
}
}
/* ****** That's it -- you're done with the loops. ******* */
// END Version 3
/* DO IT:
Optional fun: Remove the trailing comma on the last extra.
HINT: use the length property and the substr() method.
*/
// Version 1
// DO IT: Assign the total to the txtTotal textbox. Include a dollar sign and use .toFixed() to display 2 decimal places
document.getElementById("txtTotal").value = "$" + parseFloat(g_fTotal).toFixed(2); //Got help from stack overflow with the parseFloat than researched on w3schools on how to use it.
} // function CalculateTotal
// Version 2
/* DO IT:
Declare function GetSandwichName().
This function takes one parameter, named p_iSandwichIndex,
which is a radSandwich radio button index, i.e. the index of the Sandwich they selected.
It assigns the value of the selected sandwich to a global var name g_sSandwich.
*/
// END Version 2
// Version 2
/* DO IT:
Declare function GetSizeUpdateTotal().
This function takes one parameter, named p_iSizeIndex, which is a radSize radio button index,
i.e. the index of the radSize radio button that they selected.
The function should assign the *value* of the selected size to a global var name g_sSize.
Also, it must update the Total with the price for the size they selected.
The price is located in the title attribute of the radio button (take a look).
Remember that (using dot notation) you can access any object attribute you want, once you grab the object.
But the price in the title attribute contains a dollar sign,
and you want everything AFTER the dollar sign.
Use the substr() method to get the entire string, starting with the SECOND character in the string.
Look back on our class notes to see how we did this.
Use an alert to see that you got what you intended.
Then, convert that string to a number and add it to the Total.
TIP: Declare local vars as necessary.
*/
// Version 2
/* DO IT:
Declare function GetExtraUpdateTotal().
This function takes one parameter, named p_iExtraIndex, which is a chkExtras checkbox index, i.e. the index of an extra they selected.
Use an if statement to see if this particular checkbox is checked. If it is, then do the following:
Concatenate the value of the selected extra to a global var name g_sExtras.
Update the Total with the price of the Extra.
*/
function ProcessOrder() {
// This function should run when the ProcessOrder button is clicked.
// Version 2
// DO IT: declare any local vars you may need
var txtName = document.getElementById("txtName");
var txtMonth = document.getElementById("txtMonth");
var selPayment = document.getElementById("selPayment");
var selYear = document.getElementById("selYear");
var txtCreditCardNbr = document.getElementById("txtCreditCardNbr");
var month;
// Version 2
// DO IT: Before you do your error checking, does anything need to be initialized to an empty string? Now's the time to do it.
document.getElementById("divOrder").innerHTML = "";
g_divErrors.innerHTML = "";
// Version 2
// DO IT: If the name field is blank, display "Enter customer's name", set the focus and get out.
if (txtName.value === "") {
g_divErrors.innerHTML = "Enter customer's name";
txtName.focus();
return;
}
// Version 2
/* DO IT: Credit Card Code
Use an IF statement to determine if the user selected the credit card option in the selPayment dropdown
If they did, you need to do the following:
if the credit card number field was left blank or the contents of the field is not a number, display (in divErrors) the message shown in the working version, put focus on the card number field and get out.
if the month field was left blank or the contents of the field is not a number, display the message shown in the working version, put focus on the month field and get out.
if the month they entered is less than 1 or > 12, display the message shown in the working version, put focus on the month field and get out.
TIP: Remember to convert the txtMonth value to a number before you do your comparison.
if they neglected to select a year, display the message shown in the working version, put focus on the year field and get out.
*/
// END Version 2
// The following section I got assistance from another classmate.
if (selPayment.selectedIndex === 2) {
if ((txtCreditCardNbr.value === "") || (isDigits(txtCreditCardNbr.value) === false)) {
g_divErrors.innerHTML = "Enter your card number using only digits";
txtCreditCardNbr.focus();
return;
} else if ((txtMonth.value === "") || (isDigits(txtMonth.value) === false)) {
g_divErrors.innerHTML = "Enter month using only digits";
txtMonth.focus();
return;
} else {
month = Number(txtMonth.value);
if ((month < 1) || (month > 12)) {
g_divErrors.innerHTML = "Enter month between 1 and 12";
txtMonth.focus();
return;
}
}
if (selYear.selectedIndex === 0) {
g_divErrors.innerHTML = "Please select a year";
selYear.focus();
return;
}
}
// DO IT: Concatenate the appropriate msg into divOrder. The Welcome msg is within an h3 tag. Every other line is within a p tag. The last line is in bold.
/* Version 1:
Do not include the user's name in the welcome message.
Do not include the "Paid by" statement.
*/
/* Version 2:
Include the user's name in the welcome message.
Include the "Paid by" statement.
*/
document.getElementById("divOrder").innerHTML =
"<h3>Welcome to Dirty Deli!</h3>" + txtName.value + "<br>" +
"You have ordered a " + g_sSize + " " + g_sSandwich + " with " + g_sExtras + "<br>" +
"Your total is " + document.getElementById("txtTotal").value + "<br>" +
"Paid with " + selPayment.value + "<br>" + "<br>" +
"<strong>Have a nice day!</strong>";
} // function ProcessOrder
g_radSize is an array of (one or two )array. hence the loop is running for amount of elements g_radSize contain.
Normally, you should be using g_chkExtras.length instead of g_radSize.length.
for (i = 0; i < g_chkExtras.length; i++) {
if (g_chkExtras[i].checked === true) {
g_sExtras += g_chkExtras[i].value + ", ";
g_fTotal += gc_fExtrasPrice;
}
}