It is a beautiful Saturday in the Twin Cities of Minneapolis and St. Paul. My wife and I will be going for a 5 mile walk later this morning.
Today I woke up around 04:00 AM. It was somewhat warm at home. Turned off heating and opened a window. Since then the inside temperature had dropped to a more comfortable 68 degrees F.
This morning I read a post titled The Middle Class is being Disrupted by the One Percent by Michael K. Spencer on Medium. The post is quite interesting to me. The reason being is that I have been thinking and discussing with friends and family similar ideas. Something needs to be done by companies and governments before Capitalism and Democracy becomes a chapter in a history book.
As I have mentioned many times in this blog, I dedicate every work day a 2-hour block (on weekends I go with 2 or 3 blocks per day) of my time learning. I believe that reading, watching videos and taking online courses is the only way to avoid obsolescence in the rapid changing world we live in.
I just finished watching the video JavaScript Tutorial & JavaScript Projects. In this case the video runs for about 44 minutes, but I spent over 6 hours watching, pausing, experimenting, and to some extent enhancing the code. You should always stand on the shoulders of giants.
The video is the first of a series. I will probably end watching them all. Given that this is the first one some tools and libraries need to be installed. The tutorial uses Visual Studio Code which happens to be my goto IDE when I work with JavaScript (JS). I did install the Code Runner extension. I have found that it is always a good idea to match the tools and in some cases versions of the frameworks and libraries in order to eliminate issues. When I write code for a post, I always test it to make sure it works before uploading to GitHub. If you run into an issue with contents, chances are that you have a typo or there is an issue with versions.
Please note that I am using a Windows 10 machine for this post. It was the sensible because of Visual Studio Code. That said, Microsoft offers version for these platforms: Linux and macOS. To be honest with you, I have been using Visual Studio for a couple decades and have developed millions of lines of code for different products and services. Currently I have about a dozen IDEs installed in this machine and 4 of them are versions of Visual Studio.
I created a project named js_proj and installed on my machine Bootstrap. Bootstrap is an open source toolkit for developing HTML, CSS and JavaScript code. We will be creating three files as illustrated by the following:
C:\Users\John\js_proj>dir Volume in drive C is OS Volume Serial Number is 26E8-87B0 Directory of C:\Users\John\js_proj 04/20/2019 05:36 AM <DIR> . 04/20/2019 05:36 AM <DIR> .. 04/20/2019 05:36 AM 24 .jshintrc 04/19/2019 11:45 AM 3,562 js_proj.html <==== 04/20/2019 06:12 AM 4,031 js_proj.js <==== 04/18/2019 11:47 AM 141 mainstyle.css <==== 4 File(s) 7,758 bytes 2 Dir(s) 573,298,171,904 bytes free
I started with a base HTML file as illustrated here:
<!DOCTYPE html> <html lang="eng"> <head> <meta charset="utf-8"> <meta name="viewport" content="width = device-width, initial-scale = 1"> <title>JavaScript Project</title> </head> <body> </body> </html>
The following notes contain instructions from the video, which added support to the project for Bootstrap:
https://getbootstrap.com/docs/4.3/getting-started/download/ BootstrapCDN Skip the download with BootstrapCDN to deliver cached version of Bootstrap’s compiled CSS and JS to your project. Copy and insert into js_proj.html: <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22https%3A%2F%2Fstackpath.bootstrapcdn.com%2Fbootstrap%2F4.3.1%2Fjs%2Fbootstrap.min.js%22%20integrity%3D%22sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf%2FnJGzIxFDsf4x0xIM%2BB07jRM%22%20crossorigin%3D%22anonymous%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> Copy and insert into js_proj.html: <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22https%3A%2F%2Fcode.jquery.com%2Fjquery-3.3.1.slim.min.js%22%20integrity%3D%22sha384-q8i%2FX%2B965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH%2B8abtTE1Pi6jizo%22%20crossorigin%3D%22anonymous%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fpopper.js%2F1.14.7%2Fumd%2Fpopper.min.js%22%20integrity%3D%22sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1%22%20crossorigin%3D%22anonymous%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" />
The URL to download and look for what you need is in the last note. Follows are two pieces of code that need to be inserted into the js_proj.html file.
When all is set and done configuring Bootstrap, your js_proj.html file should look as follows:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width = device-width, initial-scale = 1" /> <title>JavaScript Project</title> <!-- **** from: BootstrapCDN **** --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" /> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22https%3A%2F%2Fstackpath.bootstrapcdn.com%2Fbootstrap%2F4.3.1%2Fjs%2Fbootstrap.min.js%22%20integrity%3D%22sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf%2FnJGzIxFDsf4x0xIM%2BB07jRM%22%20crossorigin%3D%22anonymous%22%20%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> </head> <body> <!-- **** include CDN versions of jQuery and Popper.js **** --> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22https%3A%2F%2Fcode.jquery.com%2Fjquery-3.3.1.slim.min.js%22%20integrity%3D%22sha384-q8i%2FX%2B965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH%2B8abtTE1Pi6jizo%22%20crossorigin%3D%22anonymous%22%20%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fpopper.js%2F1.14.7%2Fumd%2Fpopper.min.js%22%20integrity%3D%22sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1%22%20crossorigin%3D%22anonymous%22%20%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> </body> </html>
The idea is to generate a web page with a set of buttons and an output section. The buttons are separated into two sets. The first set is used to provide replacement text for placeholders (defined by a ~) in sentence. The second set is used to display an alert dialog, call a function to generate an estimated value for PI, generate the first few numbers in the Fibonacci sequence, and finally the most interesting part of the code, the display of the sentence using the words you specify in the first set of buttons.
You can watch the video and download the code provided by the author. I will go over some changes I made to the code as I was writing and experimenting. I will provide comments as we look into the software.
The final js_proj.html file follows:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width = device-width, initial-scale = 1" /> <title>JavaScript Project</title> <!-- **** from: BootstrapCDN **** --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" /> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22https%3A%2F%2Fstackpath.bootstrapcdn.com%2Fbootstrap%2F4.3.1%2Fjs%2Fbootstrap.min.js%22%20integrity%3D%22sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf%2FnJGzIxFDsf4x0xIM%2BB07jRM%22%20crossorigin%3D%22anonymous%22%20%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> <!-- **** link to our own style sheet **** --> <link rel="stylesheet" type="text/css" href="mainstyle.css" /> <!-- **** link to our javascript **** --> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22js_proj.js%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> </head> <body> <!-- **** add bootstrap code for our app **** --> <div class="container"> <div class="jumbotron"> <h3>MadLib Generator</h3> <form class="form-inline"> <input type="text" class="form-control" id="i0" value="Person" /> <input type="text" class="form-control" id="i1" value="Noun" /> <input type="text" class="form-control" id="i2" value="Verb" /> <input type="text" class="form-control" id="i3" value="Verb" /> <input type="text" class="form-control" id="i4" value="Verb" /> <input type="text" class="form-control" id="i5" value="Verb" /> <input type="text" class="form-control" id="i6" value="Plural Verb" /> <input type="text" class="form-control" id="i7" value="Verb" /> <input type="text" class="form-control" id="i8" value="Adjective" /> <input type="text" class="form-control" id="i9" value="Noun" /> <input type="text" class="form-control" id="i10" value="Event" /> <input type="text" class="form-control" id="i11" value="Noun" /> <input type="text" class="form-control" id="i12" value="Body Part" /> <input type="text" class="form-control" id="i13" value="Noun" /> </form> <button type="submit" class="btn-lg" onClick="alert('Hello John')"> Hello </button> <button type="submit" class="btn-lg" onClick="calcPI(100000000)"> PI </button> <button type="submit" class="btn-lg" onClick="getFibList(20)"> Fibonacci </button> <button type="submit" class="btn-lg" onClick="madLibGenerator()"> MadLib Generate </button> <div class="input_group"> <div class="input-group-prepend"> <span class="input-group-text">Output</span> </div> <textarea id="output1" rows="18" class="form-control"></textarea> </div> </div> </div> <!-- **** include CDN versions of jQuery and Popper.js **** --> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22https%3A%2F%2Fcode.jquery.com%2Fjquery-3.3.1.slim.min.js%22%20integrity%3D%22sha384-q8i%2FX%2B965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH%2B8abtTE1Pi6jizo%22%20crossorigin%3D%22anonymous%22%20%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fpopper.js%2F1.14.7%2Fumd%2Fpopper.min.js%22%20integrity%3D%22sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1%22%20crossorigin%3D%22anonymous%22%20%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /> </body> </html>
In the body we add the code for our application. We are using Bootstrap classes. You can see that the first set of buttons used to specify replacement words, contains 14 buttons. Note how the buttons were labeled. It will become obvious when we look at the JS code.
The first onClick() function does not need much elaboration. The following two have arguments. They will become clear when we visit the JS code. The madLibGenerator() function is the most interesting of the callbacks.
Let’s start with the JS code by looking at the calcPI() function in the js_proj.js file:
/* * Compute the value of PI to some precision using a series. */ function calcPI(iterations) { let pi = 0.0; let divisor = 1; // **** loop once per pair of terms **** for (i = 0; i <= iterations; i++) { // **** compute the next two terms in the series **** pi += 4.0 / divisor - 4.0 / (divisor + 2); // **** update the divisor **** divisor += 4; } // **** output the value (should be in a separate method) **** document.getElementById("output1").value = pi.toFixed(10); }
The function expects a number to specify the number of times the main loop needs to execute. We are using the Gregoty-Leibniz infinite series to calculate the value of PI. I cover this topic on Calculate Pi post in this blog. In this approach we calculate 2 consecutive elements in the series.
Note that depending on your computer, when you click on the <PI> button on the browser, it may take a few seconds to generate the value for PI. In a real application we would probably put a message in the output pane and then wait for an event when the call completes in order to display the result.
The next button <Fibonacci> is used to generate the first 20 numbers in the Fibonacci series. The code for the Fibonacci numbers follows:
// **** to store Fibonacci sequence **** let fibList = []; /* * */ function getFibList(count) { // **** loop populating the array **** for (i = 0; i < count; i++) { fibList[i] = fib(i); } // **** manipulate list (if needed) **** // fibList.shift(0); // remove first element // fibList.pop(); // remove last element // fibList.splice(3, 1); // remove specified element // **** output the list (should be in a separate method) **** document.getElementById("output1").value = fibList.join(", "); } /* * Compute the specified Fibonacci number * 0 1 1 2 3 5 8 13 21 34 55 ... */ function fib(whichNum) { // **** for starters **** let num1 = 1; let num2 = 0; let temp = 0; let i = 0; // **** loop until the specified number **** while (i < whichNum) { temp = num1; num1 += num2; num2 = temp; i++; } // **** return the Fibonacci number **** return num2; } // // **** test fib() **** // for (i = 0; i < 10; i++) { // let f = fib(i); // console.log(`i: ${i} f: ${f}`); // }
I have also written a post on Fibonacci Sequence in this blog.
The code starts with the declaration of an array which we will use to hold the Fibonacci numbers. The getFibList() function is the callback function which in our case specifies the first 20 values in the sequence (see the js_proj.html file). The numbers are created by calling the fib() function specifying which number to generate. The author of the video points out that there are better ways to generate the sequence, but his approach is to use simple yet not efficient code. You can see that when generating a number in the sequence, the code in fib() generates all numbers every time. Also this code is not re entrant.
I spent some time experimenting with the code. This is why I left behind some commented code.
Now for the start of the show, the code that takes a sentence and replaces all the words using the values specified by the user. The code follows:
// **** mad library text **** let mLText = `My dear old ~ sat me down to hear some words of wisdom. \n 1. Give a man a ~ and you ~ him for a day ~ a man to ~ and he'll ~ forever \n 2. He who ~ at the right time can ~ again \n 3. Always wear ~ ~ in case you're in a ~ \n 4. Don't use your ~ to wipe your ~ - Always have a clean ~ with you `; // **** convert string into array **** let mLArray = mLText.split(" "); // **** array for user input **** let inputArray = []; /* * */ function madLibGenerator() { // **** convert string into array **** mLArray.length = 0; mLArray = mLText.split(" "); // **** array for user input **** inputArray.length = 0; // **** populate array with input values **** createInputArray(); // **** check if values are missing **** if (checkForMissingInput()) { document.getElementById("output1").value = "Please enter all values above"; } else { // **** replace ~ with user specified words **** createMLSentence(); } } /* * Populate array with input values. */ function createInputArray() { // **** clear the input array **** inputArray.length = 0; // **** 14 entries in the HTML file **** for (i = 0; i <= 13; i++) { inputArray[i] = document.getElementById("i" + i).value; } } /* * Check for missing input by comparing default with current values. */ function checkForMissingInput() { // **** list of defualt values **** let defaultArrayVals = [ "Person", "Noun", "Verb", "Adjective", "Plural Verb", "Body Part", "Event" ]; // **** traverse the values in the input array **** for (i = 0; i < inputArray.length; i++) { // **** check for missing value **** if (defaultArrayVals.indexOf(inputArray[i]) > -1) { return true; } } // **** no missing values **** return false; } /* * Create the mad library sentence by replacing ~ with * values entered by user. */ function createMLSentence() { // **** traverse the array of words in the mad library sentence **** let arrIndex = 0; for (i = 0; i < mLArray.length; i++) { let matchIndex = mLArray.indexOf("~"); mLArray[matchIndex] = inputArray[arrIndex++]; } // **** output the mad library sentence (should be in a separate method) **** document.getElementById("output1").value = mLArray.join(" "); }
The code starts by defining the base text with several instances of the ~ character. Based on how the code works, we cannot follow a ~ with “~.” This is due to the fact that we will split the text into words separated by a single space “ “. A regular expression would work here if you are interested in having such option.
I deviate from the code in the video because if you want to change a word in the text, it will not do it. The issue is that we just append our changes which never get displayed. Because I wanted to just edit a value at a time, I changed the declaration for the mLArray and added a couple lines at the top of the madLibGenerator() function.
The code for the madLibGenerator() function is simple and elegant. It populates an array with the values in the 14 buttons. Checking for missing input is done by checking the values against the labels (first values entered in each of the 14 buttons) at the start of the application. Note that some of the values / labels are repeated and that is fine.
Once we have the arrays ready, we replace the ‘~’ with the words specified by the user.
Note that in some places in my comments I added the string “(should be in a separate method)”. This is not required in this example, but as a design pattern, you do not want to have a function / method do more than one thing. In these cases we make computations and displaying results. If something changes in the way we display, we have to update multiple functions. A simple refactoring operation would take care of this issue. The design pattern is called “SRP: The Single Responsibility Principle” and is the ‘S’ in the SOLID design principles. I wrote a post on SOLID in this blog.
If you are interested the code that I wrote for this post it is located in my GitHub repository.
If you are interested in learning make sure you read and experiment. It is the best way to learn!
If you have comments or questions regarding this or any other post in this blog, or if you would like me to help with any phase in the SDLC (Software Development Life Cycle) of a product or service, please do not hesitate and leave me a note below. Requests for help will remain private.
John
Follow me on Twitter: @john_canessa