Posted in freecodecamp, tutorial, web dev

Learn Functional Programming by Building a Spreadsheet

freecodecamp.com tutorial

**This is not meant to be a tutorial or a guide on how to complete the tutorial. This is just my thought process and notes as I go through the steps myself.**

Very interested in this one because I think it’ll help with some of the ideas I have for the future (like accounting adjacent stuff). Going to try to keep it brief this time, maybe only touch on the steps that I have to think about.

First step is to generate cells for the spreadsheet. I will use the window object to create containers (divs) when the page loads with the onload property. There is already a div in the HTML with the ID of “container.”

window.onload = () => {
  const container = document.getElementById("container")
}

Nested functions are great for when a function needs to reuse logic. I will use a nested function inside of the above one to create new div elements on the page.

Inside of the nested function I will also assign a class name to the new div by using .className and change the .textContent of the new divs to be the value of the name parameter. Lastly, the div will be appended to the container element (which is a different div). Because all of this is inside the .onload event, it will happen as soon as the page loads.

window.onload = () => {
  const container = document.getElementById("container");
  const createLabel = (name) => {
    const label = document.createElement("div");
    label.className = "label";
    label.textContent = name;
    container.appendChild(label);
  }
}

Next I need a function to generate a range of numbers (called range). I will do this using start and end as parameters, and the Array() constructor to return an empty array. The .fill() method is used to fill the array with the start value. Then the .map() method is used to iterate over the array and transform each element in the array according to the given function. In this instance I will be using element and index as parameters, and add them together to get the new element value to put in the array.

const range = (start, end) => Array(end - start + 1).fill(start).map((element, index) => element + index);

This same function pattern can be used to create a range of letters. The start and end parameters in this function, however, will be letters. (I am thinking this is going to be the letters going down the side to designate the cells. It would have been nice if they explained what we were doing before telling us to do it).

To do this, the .charCodeAt() method is used. This method returns a Unicode number that should correspond with the letter that is needed. A 0 is used as the argument. This will be added to both start and end.

As before, range() will return an array of numbers, which will need to be converted back into characters. The .map() method can help with this. It will be chained to the range() function call and have a callback function with String.fromCharCode() in the body. This method returns a string from a sequence of Unicode (UTF-16) values.

After that, I assign the charRange() function to the the variable letters with the letters A and J as arguments. This causes the browser to display the letters A – J across the top of the page with the addition of some pre-written CSS.

Calling letters.forEach(createLabel) will call the function createLabel() that is nested inside of the window.onload event. This nested function is the one that creates the divs for the document. The range() function returns an array, so array methods can be chained to it. Then we do a similar process for the numbers that would typically be found across the left-hand side of a spreadsheet.

The next step was asking to create an input element and set the type and ID. Creating the element was easy, but I was unsure of the syntax for adding the type and ID. I tried input.type(“text”) and that wasn’t correct (at least according to the exercise, maybe it is an alternative way to do it, unsure at this point). I also tried input.setAttribute(“text”) which didn’t work (also unsure if this is an alternative correct way to do it). I tried setAttribute() for ID as well but it didn’t work that way. The exercise wanted the following:

    letters.forEach(letter => {
      const input = document.createElement("input");
      input.type = "text";
      input.id = letter + number;
    })

The next step explains the syntax that the previous step wanted so I’m wondering if they edited the steps and should have put some of the instruction that’s in 18 on step 17. All they’re asking in 18 is to set the aria label (very important for screen readers), and then after they ask to append the input element as a child to the container div.

Working on built in functions for the spreadsheet to add numbers together etc. Must remember that .reduce() requires a callback function with two parameters, and ideally a starting number (at the end).

const sum = (nums) => nums.reduce((nums, currentValue) => nums + currentValue, 0);

Next I will use the sum() function in the newly created average() function to find the average of the array:

const average = (nums) => sum(nums) / nums.length;

I had a bit of trouble with .slice() and .sort() again.

onst median = (nums) => {
  const sorted = (nums) => nums.slice().sort((a,b) => a - b)
}

I had an extra arrow function that wasn’t needed.
This is the correct way to do it:

const median = (nums) => {
  const sorted = nums.slice().sort((a,b) => a - b)
}

The next part I need to use a Ternary to check if the length of the array is even or not. I always think Ternary operators are cool, not sure why. Maybe it’s the simplicity. Anyway, this is another one I was having trouble with. There are a lot of variables that need to be passed into the correct areas and since I still don’t have a full grasp on referencing indexes in arrays, I think that’s why it was a bit confusing for me.

Normally this would all be written on one line but I wanted to explain the parts and it was easier to do on different lines.

return isEven(length)     // this calls the isEven() function and passes the variable length as the argument
? average(sorted[middle], sorted[middle +1]     // this one calls the average() function and passes in the sorted array with the index calculated with the *middle* variable if isEven(length) returns true
: sorted[Math.ceil(middle)]     // the last part takes the value from the *middle* variable of the sorted array and rounds it up using Math.ceil.

All on one line it would be:

return isEven(length) ? average([sorted[middle], sorted[middle +1]]) : sorted[Math.ceil(middle)]

I was going to try to just do one tutorial per post from now on, but I’m having a not so great mental health day so I think I’m going to stop for now. Hopefully tomorrow is better.

Author:

Web Developer with art and design experience - recently laid off and using my free time to learn more.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.