Advanced Modern JavaScript

 ES stands for ECMAScript, a standard for coding, and JavaScript landing standards. So JavaScript added to ECMA standard back in 1997 and then we have a lot of ES standards now, which is a standard JavaScript implementation.

Var is used within global, function scope, and local scope, and let and const is used for block scoping where value can change. Let's create a graph that understands scope. Function scope is a scope with an individual function. Defined in block scope means that we can't access it within a block. const acts just acts like the block scope, where the value can't change. You can change when you go to in regards to the let. We use let and const to be able to have restrictions in the scope. 



 Defining var is within function scope, but last name is defined in the block scope, which means we can't access it anywhere outside of the block. 


Here's the function:


function letVarExample() {

    if(true) {

        var firstName = "Chris";

        let lastName = "Chu";

        const middleName = "Wei";

    }

    console.log("Function Scope Access: ", firstName); 

    console.log("Function Scope Access: ", lastName); //DOES NOT WORK

    console.log("Function Scope Access: ", middleName); //DOES NOT WORK

}


Moving forward we'll use let and const now. 

Template literals does string interpolation and allow embedded expressions. String interpolation allows strings, and embedded expressions allow us to do calculations with strings. We can use backticks for string interpolation to create one piece of string for like "Firstname space lastname". or we can also get an if else case in this circumstance. 

instead of let fullName = firstname + " " + lastName we can do 

let fullName = `${firstName} ${lastName}`

You can also use template literals. 

var output = `${searchResults > 0 ?   `${searchResults} results `  :  'No search results' }`;

Arrow functions are a way to compactly run functions.

func = (ex1, ex2) => {return ex1}; 



Let's replace a function called getFullName(). 


getFullName = () => {

    let firstName = "Chris"; 

    let lastName = "Chu"

    return `${firstName} ${lastName}`;

}


getFullNameShorter = {firstName, lastName} => console.log(`${firstName} ${lastName}`);


Default parameters allow us to set default values for dunction parameters. We can set a default value first. 

funct = (ex1 = "default value", ex2) => {

    return ex1; 

}


There's also a sort by and we can sort by a particular type. If there's no value, it uses a default value, even if there are no parameters. 


sortBy (sortType = "Name", users) => {

    console.log("Sorting By: ", sortType);

}

sortBy("Date", []); //this prints date. 

sortBy(); // this just prints name

We can define iterations using ES6.


The first way to interate means you just have a for loop but we have more efficient ways to do this! We can use a for each loop or let value of... to iterate through every value of the array, and myArray.map works almost exactly as forEach, but has a few differences. 



for(let fruit of fruits) {

    console.log(fruit);

}


fruits.forEach((fruit) => {

    console.log(fruit);

})



fruits.forEach((fruit, index) => {

    console.log(fruits[index]);

    return fruit;

})




MAPPING

newFruits = fruits.map((fruit) => {

    console.log(fruit);

    return fruit;

});

console.log(newFruits);


returning the fruit will get the output array and this can be useful because we retun a new array that we can use to modify inside of this function, using fancy string interpolation and various other things. This is the biggest difference between .map() and .forEach(). 

Now we can try to do a .filter with a value and see if the value equals something return false else we're going to return true. 


newFruits = fruits.map((fruit) => {

    return fruit;

}).filter((value) => {

    if(value == "banana) {

        return false;

    }   else {

        return true; 

    }

})

this line of code returns things that do not exist. We can destructure objects. Before we did the following: 


let fullName = {

    firstName: "Christopher", 

    lastName: "Chu";

}

let firstName = fullName .firstName;

let lastName = fullName.lastName; 


VS

const {firstName, lastName } = fullName and it constructs the object. 

.

We can also have an array deconstructor. The cool thing about JavaScript is that we can have an array and a function inside of the same line.

if we do like 

let [a, b, c] = [d, e, f] where a maps to d, b maps to e, and c maps to f. 


let user = [

{firstName: "Elon", lastName: "Musk"},

(user) => {

    console.log("I made the rocket!", user);

}

]


The following commend will store object in newUser and the print string in setUser. 


let [newUser, setUser] = user; 

Notice that this is also in block scope. 


Now a new project is to convert texteditor project to ES6, which the texteditor has the link in the description wehere we will be able to see, download, and use, and we'll have a texteditor that we can type format, center line, left line, right line, etc. Remember, in the past, this project was formatted, mainly as a DOM object. 


Here's the HTML Code:

<!DOCTYPE html>

<html>

  <head>

    <meta charset="utf-8">

    <meta name="viewport" content="width=device-width">

    <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">

    <script src="https://kit.fontawesome.com/c939d0e917.js" crossorigin="anonymous"></script>

    <title>repl.it</title>

    <link href="style.css" rel="stylesheet" type="text/css" />

  </head>

  <body class="text-center container">

    <main>

        <h1 class="banner p-3 text-primary">TextEditor</h1>

        <div class="row">

          <div class="col">

            <button id="bold" type="button" onclick="makeBold(this)" class="btn btn-light">Bolb</button>

            <button id="italic" type="button" onclick="makeItalic(this)" class="btn btn-light">Italic</button>

            <button id="underline" type="button" onclick="makeUnderline(this)" class="btn btn-light">Underline</button>

            <button id="left-align" type="button" onclick="alignText(this, 'left')" class="align btn btn-light"><i class="fas fa-align-left"></i></button>

            <button id="center-align" type="button" onclick="alignText(this, 'center')" class="align btn btn-light"><i class="fas fa-align-center"></i></button>

            <button id="right-align" type="button" onclick="alignText(this, 'right')" class="align btn btn-light"><i class="fas fa-align-right"></i></button>

          </div>

        </div>

        <hr />

        <div class="row editor">

          <div class="col">

            <div class="form-group">

              <label for="text-input">Your Document Text</label>

              <textarea class="form-control" id="text-input" oninput="updateText()" rows="3"></textarea>

          </div>

          </div>

          <div class="col">

            <label for="text-input">Formatted Text</label>

            <div id="text-output" class="bg-light">

            </div>

          </div>

        </div>

    </main>

    <script src="script.js"></script>

  </body>

</html>


JavaScript:


 function updateText(){

    let text = document.getElementById("text-input").value;

    document.getElementById('text-output').innerText = text;

  }

  

  function makeBold(elem){

    elem.classList.toggle('active');

    document.getElementById('text-output').classList.toggle('bold');

  }

  

  function makeItalic(elem){

    elem.classList.toggle('active');

    document.getElementById('text-output').classList.toggle('italic');

  }

  

  function makeUnderline(elem){

      elem.classList.toggle('active');

      let output = document.getElementById('text-output');

      if(output.classList.contains('underline')){

        output.classList.remove('underline');

      } else {

        output.classList.add('underline');

      }

  }

  

  function alignText(elem, alignType){

    document.getElementById('text-output').style.textAlign = alignType;

    let alignButtons = document.getElementsByClassName('align');

    for(let i = 0; i < alignButtons.length; i++ ){

      alignButtons[i].classList.remove('active');

    }

    elem.classList.toggle('active');

  }


CSS:

#text-output {

    min-height: 200px;

    border-radius: 3px;

    padding: 10px;

    word-wrap: break-word;

    text-align: left;    

}



#text-input {

    min-height: 200px;

}


.editor .col {

    max-width: 50%;

    flex-basis: 50%;

}


.bold{

    font-weight: bold;

}


.italic {

    font-weight: italic;

}


.underline {

    text-decoration: underline;

}


Now, time for the ES6 edits! We add '=' and '=>' and we change the for loop to change and use the .map() function instead. Here, align buttons is an html collection, gut we don't contain a foreach or .map function so to fix this, we need to use an external looping function. You can also replace for clauses with (let ... of), etc. 


Here's the final code, with changes in dark green: 


  updateText = () => {

    let text = document.getElementById("text-input").value;

    document.getElementById('text-output').innerText = text;

  }

  

  makeBold = (elem) => {

    elem.classList.toggle('active');

    document.getElementById('text-output').classList.toggle('bold');

  }

  

  makeItalic = (elem) => {

    elem.classList.toggle('active');

    document.getElementById('text-output').classList.toggle('italic');

  }

  

 makeUnderline = (elem) => {

      elem.classList.toggle('active');

      let output = document.getElementById('text-output');

      if(output.classList.contains('underline')){

        output.classList.remove('underline');

      } else {

        output.classList.add('underline');

      }

  }

  

alignText = (elem, alignType) => {

    document.getElementById('text-output').style.textAlign = alignType;

    let alignButtons = document.getElementsByClassName('align');

    for(let button of alignButtons) {

        button.classList.remove('active');

    }

    elem.classList.toggle('active');

  }


The next topic to go through is promises which allow us to run code in the future once some other work is completed. There's a function, and think of the function as loading. A task is resolved once it is finished but once it is not finished the task gets rejected. Setting up a promise is very simple, and the promise has 2 parameters, and these 2 parameters are resolve and reject, and inside the function, you can basically do anything you want. You can do the set timeout after 1,000 miliseconds, and resolve a function, which indicates, "Here is my value after the completion of a task. 

.then() is indicated for success and .catch() is indicated for reject. Calling APIs and trying to get data from APIs call promise functions. So here's the script for both resolve and reject: 

let promise = new Promise((resolve, reject) => {

    setTimeout(() => {

        resolve({

            firstName = "Chris",

            lastName = "Chu"

        });

    }, 1000);

})

    

promise.then((response) => {

    console.log("Here is the response after 1 s: ");

    console.log(response);

})

console.log("This is part 1");


This will print ("this is part 1 first") then a response "here is a response" followed by the promise afterwards, after the timeout. you can also reject, in which there will be a catch phrase: 


let promise = new Promise((resolve, reject) => {


    setTimeout(() => {


        reject("Something went wrong");


}, 1000);

})


    


promise.then((response) => {


    console.log("Here is the response after 1 s: ");


    console.log(response);


}).catch ((error) => {


    console.log(error);


})

Now, let's fetch data from API. AJAX is Asynchronous JavaScript and XML (data that we retrieved from the API) and fetching things from the API is very big portion that we do when creating applications. 


fetch() can grab some data from certain type of websites, which you provide the URL and fetch goes there and grabs the data to the API and fetch has the logic. Fetch gets a promise which is pending. If response is 200, this means we run the result function and provide response data. However, if the response is 400, then we get into a rejected function, which says that an error has happened. 

Just with promises, fetch will return a promise, allows us to wait for the response from the API. 


This is the framework or flow of api, and let's use an api from randomuser.me. After the .then, we should be able to return response.json() and then the response.json() contains promises with all the values that we're going to need, with values and results. With .then  we can return the response data from the promise, or .catch we'll return from error. The request method will be get and we'll look at the request URL, the status codes, and more. 

We use the data in any way that we'll like. We do response.json to convert a json string into an object that we can use on the front end. 404 will be a bad url and a 200 url. 


let userPromise = fetch("https://randomuser.me/api/");

console.log(userPromise); 

userPromise.then((response) => {

    return response.json(); 

}).then((resData) => {

    console.log(resData.results[0].name.first);

    console.log(resData.results[0].name.last); 

})

.catch((error) => {

    console.log("error");

    console.log(error);

})


This will print out the error and the first and last name and console errors, etc. We can go from the console to the network tab and get things in that fashion. The "network tab" after console after "Inspect element" returns the error code from the response (error, if catch, 200 if it's successful".) 

We're gonna end up making the weather app. Remember, the main logic is going to lie in script.js. OpenWeatherMap is an open source API to retrieve weather data. Here's the solution, as well as a detailed explanation: 


The API key is very similar to a password. We need to structure the URL in the correct way. After the question mark we can get a parameters, that stands short for query, and with many parameters, separated by & and we can separate this into variables. 

CSS:

#city-input, #weather-output {

    max-width: 400px;

    margin: 0 auto;

}


.banner {

    color: #FFD23F;

    font-family: sans-serif;

}



HTML:

<!DOCTYPE html>

<html>

<head>

    <title>Weather App</title>

    <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">

    <link rel="stylesheet" type="text/css" href="style.css">

    <script src="script.js"></script>

</head>

<body class="text-center">

    <main>

        <h1 class="banner p-3">Weather</h1>

        <div class="form-group">

            <input id="city-input" class="form-control form-control-lg" type="text" placeholder="Search city">

        </div>

        <button type="button" onclick="searchCity()" class="btn btn-lg btn-dark">Search</button>

        <div id="weather-output" class="mt-3">

          <div class="card-deck mb-3 text-center">

              <div class="card mb-4 shadow-sm">

                <div class="card-header">

                  <h4 id="city-name" class="my-0 font-weight-normal">----</h4>

                </div>

                <div class="card-body">

                  <h1 id="weather-type" class="card-title">----</h1>

                  <ul class="list-unstyled mt-3 mb-4">

                    <li>Temp: <span id="temp">--</span>°</li>

                    <li>Min Temp: <span id="min-temp">--</span>°</li>

                    <li>Max Temp: <span id="max-temp">--</span>°</li>

                  </ul>

                </div>

              </div>

          </div>

        </div>

    </main>

</body>

</html>


JS:

let API_KEY = "SECRET";


getWeatherData = (city) => {

    const URL = "https://api.openweathermap.org/data/2.5/weather";

    const FULL_URL = `${URL}?q=${city}&appid=${API_KEY}&units=imperial`;

    const weatherPromise = fetch(FULL_URL);

    return weatherPromise.then((response) => {

        return response.json();

    })

}


searchCity = () => {

    const city = document.getElementById('city-input').value;

    getWeatherData(city).then((res) => {

        showWeatherData(res);

    }).catch((error) => {

        console.log(error);

        console.log("Something Happened");

    })

}


showWeatherData = (weatherData) => {

  document.getElementById("city-name").innerText = weatherData.name;

  document.getElementById("weather-type").innerText = weatherData.weather[0].main;

  document.getElementById("temp").innerText = weatherData.main.temp;

  document.getElementById("min-temp").innerText = weatherData.main.temp_min;

  document.getElementById("max-temp").innerText = weatherData.main.temp_max;

  document.getElementById("weather-output").classList.add('visible');

}



For rows and columns in HTML, invoke the <ul> and <li> tags inside of the JavaScript. There is a lot of div classes and stuff like that. The classes are mainly the bootstrap code working except for the one consisting of the input types.  In JavaScript, we are able to invoke DOM objects in setting the getElementById and inner text elements, We aggregate this as well as the method that gets the weather data to the search city, returning a .then clause that returns the response if valid but undefined if invalid.

 Then if there is an error in the searchCity() part we will catch then error, otherwise we return the data once we get it. We use .then to perform this asynchronously. Make sure to do this in the asynchronous method, only once something else is shown first indicated in the .then method (this is usually a method as an input. .resolve() and .reject() gives what to print out after the .then phase as indicated by .message() here: 





Comments

Popular Posts