Closed kitchen-boy closed 2 years ago
Summary of Module 9. 1-3: Learned:
Update function from <page-template.js> to accept one parameter: the big object of portfolio data that the <inquirer> prompts have provided us with. (right now the function can only accept 2 parameters):
Had to change the template literal data to use properties of <templateData> instead of the individual parameters (name, gitHubName)
Included a <console.log(templateData);> statement to see that the data makes it to the function when we run it!
In <app.js>, now able to use HTML template function in <page-template.js> because: -- The parameter has been renamed <templateData> to reflect that it now accepts the promise object returned by <inquirer>. -- The function definition has been changed to use the promise object's properties.
const fs = require('fs'); const generatePage = require('./src/page-template');
Copy the following commented code & place it in the function block of the second <then()> of the <promptUser()> function call.
Uncomment the expression that invokes the <generatePage()> with <portfolioData> and uses the result from our <inquirer> prompts as an argument called <portfolioData>.
A Promise chain is a series of functions that return Promises, allow us to attach <.then()**> methods to one another.
Filling out the Inquirer prompts every time you need to test something new can feel tedious and frustrating.
Bypass this step by using mock (or dummy) data as the input.
Copy the structure of the input data & provide sample answers.
Use that as the input data, saving time.
Place mock data under these expressions:
e.g. of mock data in JavaScript:
Need to disable the current function call to <promptUser()> & its corresponding promises by commenting it out:
Keep the user prompts for the final version of the app. Replace them temporarily with the expression:
const pageHTML = generatePage(mockData);
We have an object that looks like this:
We could identify data that goes into: -- a Header section -- an About section -- a Project section
Let's DESTRUCTURE <templateData> * create variables to hold data for the About & Project sections.
Update the function in <page-template.js> to have this code before the <return> statement.
Note: Can also create new variables with the array of input data earlier, BUT one big difference: -- with array destructuring, the values are destructured in the order of the array ===> we can call the variable storing the destructured array data whatever we want, AS LONG AS IT GOES IN ORDER. Array destructuring will simply go in the order of the array.
With object destructuring, we can grab any value we want out of the object by simply calling on the key name of the property we want to create a variable for. Don't have to worry about listing projects and about in any order.
NEED TO ENSURE that we're creating variable names that COMPLETELY MATCH the property name we're looking to destructure data from.
IMPORTANT: If you try to destructure a value out of an object using the wrong property key name, you won't receive an error, but that variable will have a value of <undefined>.
Change the destructuring statement as follows:
When we destructure the data from <templateData>, we create: -- the <projects> & <about> variables, AND -- taking the REST of the data that hasn't been destructured from <templateData> & storing it in a new object, called <header>.
THIS IS THE rest OPERATOR -- commonly confused with spread an identical operator in js
STUCK! # How to console.log the 3 variables???????
We'll get to this new JavaScript feature shortly; let's first confirm that it works. If we console.log() the three variables, projects, about, and now header, we'll see that all the portfolio data from templateData has now been organized into three separate sets of data. Great—now we can use this data to update the HTML template literal output!
These 2 actions are often necessary in programming:
In the JavaScript ES6 specification: operator, <...> carries out both of these actions. -- its usage dictates what we call it.
If we want to make a new array or object with the same contents as an existing array or object, we can use the spread operator, as follows:
In this example, when we create the working version for this set of data, we don't directly set the value of the original to it.
Instead, we create a new array, using its square bracket <[]> notation.
Once the JavaScript engine sees those brackets, it can infer that we're creating a brand-new set of data in memory, & then it looks at what is between the brackets.
Using the spread operator <...> , we can instruct
The other use of <...> syntax in JavaScript aka the rest operator.
The rest operator packages leftover data under a new array or object - depending on what the source of the data is - if we don't want to explicitly create data for it (or if there's an indefinite amount of data).
When we use the ... syntax on the lefthand of an assignment operator, it means we want to take the rest of the content we're destructuring and create a new array or object to hold it.
Example: Need to keep track of a car race; want to highlight first, second, & third place - while keeping the rest of the racers together.
Here is an array of drivers listed in the order that they finished the race.
Want to directly call out the drivers in first, second, & third place => use array destructuring to create variables of those first three.
Want to print out the other racer's names => use the rest operator to create a new array called
Now we have:
the data need to create a full HTML portfolio
that data organized in such a way that we can focus on one section of HTML code at a time.
The final project (without CSS styles) will look like this:
Will refactor the HTML template literal output to: -- handle the input data. -- be set up with Google Fonts, FontAwesome icons, and own style sheet.
Update the returning template literal in <page-template.js> so that the whole function looks as follows:
Used <header.name> & <header.github> as interpolated data
<header> part helps to know where this data should go & also to locate it again in the code.
Generate the current year in the footer .
The code we use there will get the current year & put it in the footer element everytime we run the app -> benefit of using string interpolation in JavaScript: we can execute valid JavaScript code inline with the text.
Save changes in the <page-template.js> file.
Enable the <fs.writeFile()> functionality in the promise chain of the <promptUser()> function call in <app.js> ==> to reincorporate the ability to write the HTML template to a file.
Uncomment the require statement at the top of <app.js> file to access the <fs> module.
Now we can write to the <index.html> file & see the dynamic input produce dynamic output as an HTML file.
HTML file should look like this:
DONE!:
Earlier, the Inquirer prompt was set up to conditionally ask for input for an About section, if the user chose to include that section.
Therefore, the <templateData> parameter might or might NOT have an <about> property present when we destructure it into an <about> variable.
When you destructure an object's property that doesn't exist, the variable for it is created but has a value of undefined.
Can't simply include <${about}> in the template literal, because we want to create an entire styled <section> HTML block to hold the content.
Need to instruct the function to ONLY RENDER that <section> element with the content if there's content to render in the first place.
Code should look like this:
Can't use <if> statements in template literals, because <if> statements don't simply return data on their own.
Whenever we use <${}> in a template literal, that indicates that data will be returned into it, and that's what gets interpolated into the content.
Create this function at the tope of <page-template.js>, above the <module.exports>:
<generateAbout()> function will accept the <about> variable as a parameter.
If it doesn't exist, we'll return an empty string <' '>.
If it EXISTS, we'll return the entire <section> element.
Update the main function's template literal:
Save <page-template.js>.
Run the app from the command line.
We'll see the About section content appear only if we enter it!
If we don't enter it, the returning HTML template will ignore it & not include that <section>.
NOTE: Executed a function from a template literal!
NEXT: the last & biggest set of data - the projects!
${generateProjects(projects)}
Now that the <generateProjects()> function is set up & being executed in the correct place, we need to deal with the project array's data.
Want the featured projects to be full-width & above the non-featured projects. Refer to following image of finished portfolio's project section - featured & non-featured projects in boxes on blue & black backgrounds:
Note: stylesheet will work similarly to Bootstrap (can create a single grid layout, then instruct certain elements to be full-width [or <col-12>] & others to not be full-width.
Focus on getting all of the projects to display first. Then add ability to organize featured & non-featured projects.
-- Can't use <.forEach()> method -- it doesn't natively return data; it just wants to use an array's data for other purposes -- it just runs the function & does nothing else -- for same reason we couldn't just nest an <if> statement to conditionally render the About section earlier.
The new array <.map()> method works a lot like the <.forEach()> method does: it takes in a function as a parameter to execute on each element in the array, which accepts each element of the array as the function's parameter. THEN the <.map()> method takes array data & uses it to create a brand-new array, thus necessitating a <return> statement.
Example of .map() method:
In this example, we have an array of animals.
We take that array, use a <.map()> method to iterate through <animalArr>, & execute a function for each animal in the array.
We take the value of <animalArr> at each iteration, which we call <animal> as the arrow function's parameter.
We return that animal followed by the words "are really cool animals."
If we logged <coolAnimalArr>, we'd see that it would be another array, but this time each element in the array would say the animal's name followed by " are really cool animals."
This is the whole POINT of the <.map()> method: to use an array of data to create a whole new set of data based on it. This doesn't affect <animalArr> at all; it just uses its data to create something new.
Update the <generateProjects()> function to look like the following:
Just updated the <generateProjects()> function to do 2 tasks:
For the projects:
Now each set of data in <projectHtmlArr> will look like the following:
All of the HTML just created has the same <col-12 col-md-6> classes for each project ==> look identical.
Want featured projects to just have <col-12> so that they run full-width -- When users answer the <featured> confirm prompt, it creates a property for each project, called <featured>, that has a value of <true> or <false> depending on how users answer.
Change the <generateProjects()> function to look like the following:
Example of the array <.filter()> method:
In this example, we have an array of ages.
We want to see which ones are over the age of 21, so we use a <.filter()> method to test each <age> one at a time.
If it's 21 or older, we return <true>, meaning that element of <.aggArr> should be included in the new <over21Arr>.
If it's younger than 21, we return <false>, meaning that element of the array shouldn't be included in the new <over21Arr>.
This is a simpler example, but we use it to test any type of data as long as we're checking for a true or false condition.
In this case, we're checking to see if the project's <feature> property is true or false.
THEN, take the arrays & use <.map()> to create the HTML content for them.
FINALLY, write it to the page in the returning <section> element.
REFACTOR the code: Change the <generateProjects()> function as follows:
Used object destructuring and learned about the rest and spread operators to help keep the data organized.
Broke a function into multiple pieces to make it easier to read the code for a specific section of the HTML template.
Leveraged HTML elements by using new array methods .filter() and .map() to take input data and return HTML data with it.
Description