Today’s coding was quite challenging, as there were a lot of math equations to solve. It took me almost an hour to figure out some of the problems. However, I enjoyed doing it once I understood what I was doing.
Earlier, I went grocery shopping for dinner. Alex requested chicken adobo, so I had to go out to buy the ingredients. Even though I had this distraction, I could still complete much work today. Later, I plan to put away my clothes since I did laundry yesterday.
Fortunately, my mental health is good today. I feel happier. I’d like to play Skyrim later if I have time. However, my physical health is not so great, as I have been having heartburn all day and haven’t eaten much. A slice of toast and some hot tea later may help me feel better.
The temperature is rising, and Spring is in the air. However, I wonder whether this trend will continue or change and become colder again. According to the weather app, the temperature will range from low to mid-60s for most of the week, except for Monday, when snow is forecasted. Interestingly, the app predicts that the temperature on Monday will be 47 degrees, which seems slightly warm for snow.
JavaScript notes…
———————————-
Building a Spreadsheet steps 1 – 25
Step 1
Your project starts with a basic HTML container and some corresponding CSS. Your first task will be to programmatically generate the cells for your spreadsheet.
The global window object represents the browser window (or tab). It has an onload property which allows you to define behavior when the window has loaded the entire page, including stylesheets and scripts.
Start by setting the onload property of window to an arrow function with no parameters. In the function, declare a container variable and assign it the value of getting the element by the id of container.
window.onload = () => { const container = document.getElementById("container"); }
Step 2
Functions are ideal for reusable logic. When a function itself needs to reuse logic, you can declare a nested function to handle that logic. Here is an example of a nested function:
const outer = () => {
const inner = () => {
};
};
Declare a nested createLabel function using arrow syntax. It should take a name parameter.
window.onload = () => { const container = document.getElementById("container"); const createLabel = (name) => { } }
Step 3
Remember that the document object has a .createElement() method which allows you to dynamically create new HTML elements.
In your createLabel function, declare a label variable and assign it a new div element.
window.onload = () => { const container = document.getElementById("container"); const createLabel = (name) => { const label = document.createElement("div"); } }
Step 4
Set the className of the label element to label, and set the textContent to the name parameter.
window.onload = () => { const container = document.getElementById("container"); const createLabel = (name) => { const label = document.createElement("div"); label.className = "label"; label.textContent = name; } }
Step 5
Finally, use the .appendChild() method to add your label element to the container element.
window.onload = () => { const container = document.getElementById("container"); const createLabel = (name) => { const label = document.createElement("div"); label.className = "label"; label.textContent = name; container.appendChild(label); } }
Step 6
You will need a function to generate a range of numbers.
Declare an empty range function which takes a start and end parameter. Use the Array() constructor and implicitly return an empty array.
const range = (start, end) => Array();
Step 7
Your array will need to be the size of the range. You can calculate this by finding the difference between end and start, and adding 1 to the result.
Pass this calculation as the argument for your Array() constructor.
const range = (start, end) => Array(end - start + 1);
Step 8
The Array() constructor has a .fill() method which can be used to fill an array with a value. You can use this to fill your array with the start value.
Chain the .fill() method to your Array() constructor, and pass it the start value.
const range = (start, end) => Array(end - start + 1).fill(start);
Step 9
Currently your range function returns an array with the correct length, but all of the values are the value of start. To fix this, chain the .map() method to your .fill() method.
Pass the .map() method a callback which takes element and index as parameters and returns the sum of those parameters.
const range = (start, end) => Array(end - start + 1).fill(start).map((element, index) => element + index);
Step 10
Now that you have a range function, you can use it to create a range of letters as well.
Declare a charRange function using const and arrow syntax. It should take a start and end parameter. The function should implicitly return the result of calling range() with start and end as the arguments.
const charRange = (start, end) => range(start, end);
Step 11
Your range function expects numbers, but your start and end values will be strings (specifically, they will be single characters such as A).
Convert your start and end values in your range() call to numbers by using the .charCodeAt() method on them, passing the number 0 as the argument to that method.
const charRange = (start, end) => range(start.charCodeAt(0), end.charCodeAt(0));
Step 12
range() will return an array of numbers, which you need to convert back into characters. Chain the .map() method to your range() call.
Pass a callback function that takes code as the parameter and implicitly returns the value of passing code to the String.fromCharCode() method.
const charRange = (start, end) => range(start.charCodeAt(0), end.charCodeAt(0)).map(code => String.fromCharCode(code));
Step 13
Now that your helper functions are complete, back in your onload event handler you should declare a letters variable. Assign it the result of calling charRange() with the letters A and J as arguments.
const letters = charRange("A", "J");
Step 14
Now call the .forEach() method of your letters array, and pass your createLabel function reference as the callback.
You should see some letters appear across the top of your spreadsheet.
letters.forEach(createLabel);
Step 15
Remember that range() returns an array, so you can chain array methods directly to the function call.
Call range() with 1 and 99 as the arguments, and chain the .forEach() method. Pass the .forEach() method an empty callback which takes number as the parameter.
range(1, 99).forEach(number => { })
Step 16
In your callback, you will need to make two function calls. Start by calling createLabel() and pass number as the argument. You should see some numbers appear in your spreadsheet.
Then call the .forEach() method on your letters array. Pass an empty callback function which takes a letter parameter.
range(1, 99).forEach(number => { createLabel(number); letters.forEach(letter => { }) })
Step 17
Now in your nested .forEach() call, declare an input variable. Use the .createElement() method of the document object to create an input element. Set the type attribute to text and the id attribute to letter + number.
letters.forEach(letter => { const input = document.createElement("input"); input.type = "text"; input.id = letter + number; })
Step 18
In earlier projects you learned about the setAttribute method. Another way to update an attribute in JavaScript is to use the following syntax:
el.attribute = value;
The property names for hyphenated HTML attribute values, such as aria-label, follow camel case, becoming ariaLabel.
el.ariaLabel = “Aria Label Value”;
Set the aria-label attribute for the input element to the same value as the id attribute.
letters.forEach(letter => { const input = document.createElement("input"); input.type = "text"; input.id = letter + number; input.ariaLabel = letter + number; })
Step 19
Append the input element to your container element as a child.
You should now be able to see the cells of your spreadsheet.
letters.forEach(letter => { const input = document.createElement("input"); input.type = "text"; input.id = letter + number; input.ariaLabel = letter + number; container.appendChild(input); })
Step 20
Most spreadsheet programs include built-in functions for calculation.
Declare a sum function that takes a nums parameter, which will be an array of numbers. It should return the result of calling reduce on the array to sum all of the numbers.
const sum = (nums) => nums.reduce((acc, el) => acc + el, 0);
Step 21
Declare an isEven function, which takes a num parameter and returns true if the number is even, and false otherwise. Use the modulo operator % to determine if a number is even or odd.
const isEven = (num) => num % 2 === 0;
Step 22
Declare an average function which takes an array of numbers as the nums parameter. It should return the average of all the numbers in the array.
The average can be calculated by dividing the sum of all the numbers in the array by the length of the array. Remember that you have a sum function you can use.
const average = (nums) => sum(nums) / nums.length;
Step 23
Your next function will calculate the median value of an array of numbers. Start by declaring a median arrow function that takes a nums parameter.
In the function, declare a sorted variable and assign it the value of sorting a copy of the nums array.
You should use the slice() method for creating a shallow copy of the array.
const median = (nums) => { const sorted = nums.slice().sort((a, b) => a - b); }
Step 24
Now declare a length variable and assign it the length of your sorted array, and a middle variable that has the value of the length divided by 2, subtracted by 1.
const median = nums => { const sorted = nums.slice().sort((a, b) => a - b); const length = sorted.length; const middle = length / 2 - 1; }
Step 25
Using ternary syntax, check if length is even using your isEven function. If it is, return the average of the number at the middle index and the number after that. If it’s odd, return the number at the middle index – you’ll need to round the middle value up.
const median = nums => { const sorted = nums.slice().sort((a, b) => a - b); const length = sorted.length; const middle = length / 2 - 1; return isEven(length) ? average([sorted[middle], sorted[middle + 1]]) : sorted[Math.ceil(middle)]; }