Categories
JavaScript

Defining and Manipulating Classes and Objects in JavaScript

In JavaScript, objects are entities that allow us to encapsulate data, functions, and other objects into one entity that we can access and manipulate. This is another fundamental building block of JavaScript programs.

Objects are used for modeling real-world data. An example would be a bird. We know that it has wings, a head, two legs, and two wings. Also, we know that it can chirp, eat, and fly.

We can model them in JavaScript by using an object. The body parts are the properties of the object, and the actions that it does are the methods.

Methods are functions that are part of the object. Properties are anything denoted with a key-value pair in JavaScript. Methods are special properties. When a property has a function as the value, it’s called a method.

For example, if we model a bird as an object, we can write:

const bird = {  
  numWings: 2,  
  numLegs: 2,  
  numHeads: 1,  
  fly(){},  
  chirp(){},  
  eat(){}  
}

fly(){}, chirp(){}, and eat(){} are methods and the rest are properties with data as values.


Creating Objects

In JavaScript, we can define objects in three ways. We can either define them as object literals, by using the object constructor method, or by using a class.

Object literal

Defining objects with object literals is straightforward. We just have to specify the properties and methods of an object directly. For example, we write:

const bird = {  
  name: 'Joe',  
  numWings: 2,  
  numLegs: 2,  
  numHeads: 1,  
  fly(){},  
  chirp(){},  
  eat(){}  
}

To define an object as an object literal.

If we want to add more properties, we write:

bird.sleep = function(){};

We can assign anything as values of object properties, so strings, booleans, functions, arrays, and other objects all can be set as properties.

Object constructor

Equivalently, we can use the object constructor method to define an object. We can write:

let bird = new Object();  
bird.name = 'Joe';  
bird.numWings = 2;  
bird.numLegs = 2;  
bird.numHeads = 1;

This is a long way to define an object. It’s slower and harder to read than object literals.

Define object instances with classes

We can also define JavaScript by first defining a class, then using the new keyword to create an object, which is an instance of the class.

To do this, we write:

class Bird {  
  constructor(name, numWings) {  
    this.name = name;  
    this.numWings = numWings;  
  } 

  logProperties() {  
    console.log(this)  
  }  
}

const bird = new Bird('Joe', 2);  
bird.logProperties();

We have the Bird class, which is a template for creating an object with the name and numWings properties and the getProperties method.

The Bird class has a constructor function that lets us pass in values for the properties and set it as properties of the object being created. It also has the logProperties function.

this is set as the object created as we aren’t using arrow functions as methods.

The object is defined by using the new keyword and passing in the data into the constructor. Once we’ve defined the object, we can call the methods defined inside it.

In this example, we called bird.logProperties to log the value of this, which should be {name: “Joe”, numWings: 2}.


Prototypes

In JavaScript, prototypes are templates that let you create other objects. They can also be used for inheritance in JavaScript. So, if we have an Animal object defined as:

function Animal(){  
  this.name = 'Joe'  
}

We can extend it by creating a new object, like so:

let bird = animal.prototype;  
bird.fly = function() {};  
bird.chirp = function() {};

Then we get the fly and chirp methods, as well as the name property in the bird object.


Defining Functions in an Object

We can define a function in an object in a few ways.

We can use the function keyword or arrow function as usual, but we can also write it with a shorthand for the function keyword. For example, if we have a bird object and we want to define the chirp function, we can write:

const bird = {  
 chirp: function(){  
   console.log('chirp', this)  
  }  
}

Or use the following shorthand:

const bird = {  
 chirp(){  
   console.log('chirp', this)  
  }  
}

The two are the same as the chirp function will have the bird object as the value of this.

On the other hand, if you use the arrow function:

const bird = {  
 chirp: () => {  
   console.log('chirp', this)  
  }  
}

this will be logged as the global window object, as arrow functions do not change the value of this to the object that the function is in.


Getting and Setting Object Properties

After an object is defined, it’s very useful to be able to get and set the properties of an object. There are two ways to get a property of an object. One is to use the dot notation, and another is the square bracket notation.

The dot notation allows us to get properties that have property names that follow the variable naming conventions. That means they start with a letter, underscore, or dollar sign and have no spaces or other special characters.

So, if we have:

const bird = {  
  name: 'Joe',  
  numWings: 2,  
  numLegs: 2,  
  numHeads: 1,  
  fly(){},  
  chirp(){},  
  eat(){}  
}

Then, we can access the name property by writing bird.name.

The alternative syntax, which is the square bracket notation, can do the same thing as the dot notation, as well as access properties dynamically.

It also lets us access properties that are defined with names that don’t follow the variable name creation rules. To use the square bracket notation to get object properties, we write: bird['name']. We can also write:

const prop = 'name';  
bird[prop];

This allows us to get properties of an object by passing in variables and string, which is handy for dynamically modifying objects and using objects as dictionaries, as we can traverse the keys and modify them as well as the values.

To set object properties with both notations, we use the assignment operator, like so:

bird.name = 'Jane';

Or, with square bracket notation, we write:

bird['name']= 'Jane';

Get All the Top-Level Properties of an Object

All JavaScript has the following functions to get all the top-level properties of an object.

Object.keys

Object.keys gets the top level list of keys of an object and returns an array of them. For example:

const a = {foo: 1, bar: 2};  
const length = Object.keys(a).length // 2

You can call find on the keys array to look for the key, like the following:

Object.keys(a).find(k => k == 'foo') // 'foo'

Object.getPropertyNames

Object.getPropertyNames also gets a list of all top levels of keys of an object and returns them as an array. For example:

const a = {foo: 1, bar: 2};  
const length = Object.getOwnPropertyNames(a).length // 2

You can call find on the keys array to look for the key, like the following:

Object.getOwnPropertyNames(a).find(k => k == 'foo') // 'foo'

for…in Loop

There is also a special loop for looping through the keys of an object. You can do the following:

const a = {foo: 1, bar: 2};  
let keysCount = 0;  
for (let key in a) {  
    keysCount++;  
}  
console.log(keysCount) // 2

Checking If an Object Property Exists

hasOwnProperty

You can check if an object has a property by calling hasOwnProperty of an object. For example:

const a = {foo: 1, bar: 2};  
a.hasOwnProperty(key); // true

Deleting Properties of an Object

JavaScript has the delete operator to remove a property of an object. If we have:

const bird = {  
  name: 'Joe',  
  numWings: 2,  
  numLegs: 2,  
  numHeads: 1,  
  fly(){},  
  chirp(){},  
  eat(){}  
}

Then we run delete bird.name, then the bird.name property will be removed. When you log it, it will log as undefined.


JavaScript Inheritance

In JavaScript, we can create classes where the properties can be included in the properties of a child class.

So, we can have a high-level class that contains the properties that are common to all the child classes, and the child class can have its own special properties that are not in any other classes.

For example, if we have an Animal class with the common properties and methods, like name and the eat method, then the Bird class can just inherit the common properties in the Animal class. They don’t have to be defined in the Bird class again.

We can write the following to do inheritance in JavaScript:

class Animal {  
  constructor(name) {  
    this.name = name;  
  }  
  eat() {  
    console.log('eat');  
  }  
}

class Bird extends Animal {  
  constructor(name, numWings) {  
    super(name);  
    this.numWings = numWings;  
  }  
}

const bird = new Bird('Joe', 2);  
console.log(bird.name)  
bird.eat();

In the example above, we have the parent class, Animal, that has the eat method, which all classes that extends from Animal will have, so they don’t have to define eat again.

We have the Bird class which extends the Animal class. Note that in the constructor of the Bird class, we have the super() function call to call the parent’s class constructor to populate the properties of the parent class in addition to the properties of the child class.


this Keyword

The this keyword allows us to access the current object’s properties inside an object unless you’re using arrow functions.

As we can see from the above example, we can get the properties of the instance of the child and the parent class in the object.


Copying Objects

Copying objects means making a new object reference to an object that has the same contents as the original.

It is used a lot to prevent modifying the original data while you assign a variable to another variable. Because if you assign a variable to a new one, the new one has the same reference as the original object.

There are a few ways to clone objects with JavaScript. Some functions do shallow copying, which means that not all levels of the object are copied, so they may still hold a reference to the original object.

A deep copy copies everything so that nothing references the original object, eliminating any confusion which arises from a shallow copy.

If you assign an object to another variable, it just assigns the reference to the original object, so both variables will point to the original object.

When one of the variables is manipulated, both will be updated. This is not always the desired behavior. To avoid this, you need to copy an object from one variable to another.

Shallow copy

In JavaScript, this is easy to do. To shallow copy an object, we can use Objec.assign(), which is built into the latest versions of JavaScript.

This function does a shallow copy, which means it only copies the top level of an object, while the deeper levels remain linked to the original object reference. This may not be desired if there are nested ones in your original object.

Here is an example of how to use Object.assign:

const a = { foo: {bar: 1 }}  
const b = Object.assign({}, a) // get a clone of a which you can change with out modifying a itself

You can also clone an array like this:

const a = [1,2,3]  
const b = Object.assign([], a) // get a clone of a which you can change with out modifying a itself

Deep copy

To do a deep copy of an object without a library, you can JSON.stringify then JSON.parse:

const a = { foo: {bar: 1, {baz: 2}}  
const b = JSON.parse(JSON.strinfy(a)) // get a clone of a which you can change without modifying a itself

This does a deep copy of an object, which means all levels of an object are cloned instead of referencing the original object.

JSON.parse and JSON.stringify only work with plain objects, which means they cannot have functions and other code that runs.

We can also use object destructuring to shallow clone objects, like so:

const a = { foo: {bar: 1}}  
const b = {...a} // get a clone of a which you can change with out modifying a itself

Now that we know how to create objects, we can easily store and manipulate data. We can create programs that do non-trivial things with the use of objects and classes.

Categories
JavaScript

Add Dynamic Styling to HTML Elements With JavaScript

An important part of turning static web pages into dynamic web apps is to dynamically change the styling of elements on the page. JavaScript lets us do this by exposing CSS properties that are part of the element as JavaScript properties that we can get or set.

DOM elements have the style object we can use to make changes to the style of DOM objects. Some things we can change with the style object includes changing text colors, changing the background color, animating objects, changing sizes, showing/hiding parts of a page, creating pop-up boxes to display things, etc.

The style is like any other DOM object in that it has many properties and methods we can use to style things. The properties are CSS properties except that all the CSS properties are converted to camel case instead of the kebab case used in CSS.

The style object returns the in-line style of an element. If you want your element to look the way you want, you have to also take into account CSS that’s external to the in-line styles of the selected element, like external CSS files and styles in style elements.

Below are some common style object properties and their CSS equivalents:

  • backgroundColor: same as the background‐color property in CSS, which gets or sets the background color of an element
  • borderWidth: same as the border-width property in CSS, which gets or sets the borders of an element
  • fontFamily: same as the font-family property in CSS, which gets or sets the font of an element
  • lineHeight: same as the line-height property in CSS, which gets or sets the height between lines of an element
  • textAlign: same as the text-align property in CSS, which gets or sets the horizontal alignment of an element

To get all the CSS properties of an element, we should use the window. getComputedStyle method to get all the CSS properties of an element. It includes all in-line CSS, external CSS, and CSS in style tags. This gets all the CSS and combines them into one object that actually contains the correct CSS styles of the element. We can use it as follows …

In index.html, we add:

<html>  
  <head>  
    <title>Get Styles</title>  
    <link href="styles.css" rel="stylesheet" type="text/css" />  
  </head>  
  <body>  
    <h1 id="title">Title</h1>  
    <h1>Styles</h1>  
    <ul id="styles-list"></ul>  
    <script src="script.js"></script>  
  </body>  
</html>

Then in script.js, we have:

window.onload = () => {  
  const title = document.getElementById("title");  
  const stylesList = document.getElementById("styles-list");  
  const titleStyles = window.getComputedStyle(title);  
  Object.keys(titleStyles).forEach(key => {  
    const li = document.createElement("li");  
    if (isNaN(+key)) {  
      li.innerHTML = \`${key}: ${titleStyles\[key\]}\`;  
      stylesList.appendChild(li);  
    }  
  });  
};

In styles.css, we add:

#title {  
  color: white;  
  background-color: lightblue;  
  font-family: Arial;  
  margin-bottom: 20px;  
  font-size: 18px;  
  font-family: monospace;  
}

With the code together, we should get:

As you can see, we have the full list of styles of the element with the ID title. As you scroll down, you will see that the fontFamily, fontSize, etc. are consistent with what we set in styles.css.


Changing Styles

To change the styles of an element, we just get the element with the usual functions, like getElementById, and then set the properties of the style object, like so:

document.getElementById('square').style.padding = '10px';

In the example above, we get the square element and then set the padding of the element with ID square to 10px. Note that we have to have px at the end for the style to be applied.


Animating Styles With JavaScript

If we want to animate an element in JavaScript, we can apply the same CSS style changes as we did before.

All we have to add is a timer delay to the execution of the style changes so it’s slow enough that we see the element’s style is being applied. To delay the execution of a piece of code in JavaScript, we can use the setTimeout function.

For example, if we want to make a box move, then we can write the following code. In index.html, we add:

<html>  
  <head>  
    <title>Animation</title>  
    <link href="styles.css" rel="stylesheet" type="text/css" />  
  </head>  
  <body>  
    <div id="box"></div>  
    <script src="script.js"></script>  
  </body>  
</html>

Then in script.js, we add:

const animate = () => {  
  const box = document.getElementById("box");  
  for (let i = 0; i < 10000; i++) {  
    (i => {  
      setTimeout(() => {  
        const left = window.getComputedStyle(box).left;  
        box.style.left = `${(+left.replace("px", "") + i * 2) %  
          window.innerWidth}px`;  
      }, 1000);  
    })(i);  
  }  
};

window.onload = () => {  
  animate();  
};

And in styles.css, we add:

#box {  
  background-color: lightcoral;  
  width: 50px;  
  height: 50px;  
  position: absolute;  
  top: 50px;  
  left: 10px;  
}

We used the setTimeout function to delay the execution of the style change to the element with the ID box by 1000 milliseconds, which is one second.

Inside the function we passed into the setTimeout function, we set the left property by getting the existing left CSS property then adding i*2 to it. Then we took the remainder divided by window.innerWidth. This lets us slide the box left and right inside the browser window.

The result is the following:


Rollover Effect

The rollover effect is the dynamic effect where the image changes when you hover over an element, and a different image is displayed when you move your mouse off them same element.

This is a common effect for showing different information when users hover their mouse over the element and then move their mouse off of it. It’s also used for other kinds of toggles. To create the effect, we have to modify an image element to show different things when the mouse is hovered over it and when the mouse is off.

The image object has the following properties:

  • alt — alt attribute of an image
  • completetrue when an image finishes loading
  • height — height of the image
  • isMap — indicates whether the image is part of an image map
  • naturalHeight — image’s original height
  • naturalWidth — image’s original width
  • src — the src attribute of the image
  • width — the width of the image element

To create the rollover effect, we can do the following. In index.html, we add:

<html>  
  <head>  
    <title>Get Styles</title>  
    <link href="styles.css" rel="stylesheet" type="text/css" />  
  </head>  
  <body>  
    <img src="images/dog1.jpg" id='dog' />  
    <script src="script.js"></script>  
  </body>  
</html>

Then in script.js, we put:

window.onload = () => {  
  const dog = document.getElementById("dog");  
  dog.addEventListener("mouseover", () => {  
    if (dog.src.includes("images/dog1.jpg")) {  
      dog.src = "images/dog2.jpg";  
    } 
    else {  
      dog.src = "images/dog1.jpg";  
    }  
  }); 

  dog.addEventListener("mouseout", () => {  
    if (dog.src.includes("images/dog1.jpg")) {  
      dog.src = "images/dog2.jpg";  
    } 
    else {  
      dog.src = "images/dog1.jpg";  
    }  
  });  
};

Finally in styles.css, we have:

#dog {  
  width: 300px;  
}

We shrank the image to 300px wide. Then in script.js, when we put our mouse over the image, we switch it to a different image.

Then when the user moves their mouse outside of the element, we toggle to another image. The two event handlers together will create the toggle rollover effect when we move our mouse back and forth inside and outside of the image.

Or, if you added the images to the folder with the files above, we should have something like:


Grow Image

To make an image grow when we hover over the mouse and then shrink back to the original size when we move the mouse outside the image, we can just handle the mouseover and mouseout events of the image.

When we hover our mouse over it, then we grow the image size; when the mouse moves out, then we shrink it back to the original size.

To do this, we put the following in index.html:

<html>  
  <head>  
    <title>Get Styles</title>  
    <link href="styles.css" rel="stylesheet" type="text/css" />  
  </head>  
  <body>  
    <img src="images/dog.jpg" id='dog' />  
    <script src="script.js"></script>  
  </body>  
</html>

Then in script.js, we put:

window.onload = () => {  
  const dog = document.getElementById("dog");  
  dog.addEventListener("mouseover", () => {  
    dog.style.width = "500px";  
  }); 

  dog.addEventListener("mouseout", () => {  
    dog.style.width = "300px";  
  });  
};

In styles.css, we add:

#dog {  
  width: 300px;  
}

The code in script.js does exactly what we just described. It changes the image size to 500px when users hover their mouse over it, then shrinks back to 300px when we move our mouse out.


Slideshow

We can manipulate our images to create a simple slideshow. All we have to do is rotate through the images we have in a set time interval with the setInterval function built into JavaScript.

In index.html, we have:

<html>  
  <head>  
    <title>Get Styles</title>  
    <link href="styles.css" rel="stylesheet" type="text/css" />  
  </head>  
  <body>  
    <img src="images/dog1.jpg" id='dog' />  
    <script src="script.js"></script>  
  </body>  
</html>

Then in script.js, we put:

window.onload = () => {  
  const dog = document.getElementById("dog");  
  const dogImgPaths = ["images/dog1.jpg", "images/dog2.jpg", "images/dog3.jpg"];  
  let index = 0;  
  setInterval(() => {  
    index = (index + 1) % dogImgPaths.length;  
    dog.src = dogImgPaths[index];  
  }, 3000);  
};

And in styles.css, we put:

#dog {  
  width: 300px;  
}

All we’re doing is rotating to a different image in our collection every three seconds by setting the path of the image in the dogImgPaths . To rotate the images we just set the index by increasing it by one and then taking the modulus with dogImgPaths.length. This way, index is always between 0 and 2 so we don’t try to get an image that doesn’t exist.


Handy Animation Properties

JavaScript has some animation properties that let us create animations by defining the key frames in CSS and then using JavaScript to control the change of the key frames to create our animation.

The following properties are provided by JavaScript to control animation:

  • animation — gets or sets all animation properties except animationPlayState
  • animationDelay — gets or sets delay before animation starts
  • animationDirection — gets or sets the direction which the animation is running
  • animationDuration — gets or sets the length of the animation
  • animationFillMode — gets or sets what happens when the animation isn’t running
  • animationIterationCount — gets or sets how many times an animation is played
  • animationName — gets or sets the list of an animation list, using CSS key-frame at rules
  • animationTimingFunction — gets or sets the speed of how an animation should run over time
  • animationPlayState — gets or sets whether the animation is running

To set the key frames of an animation in CSS, we use the keyframes property.

Making simple animations and getting and changing styles of an element isn’t too difficult with JavaScript. We can do a lot without writing too much code.

Animation is easy if we use the setTimeout and setInterval timer functions in order to delay the execution of or repeat the execution of styles when changing code.

Categories
JavaScript

How to Convert JavaScript Variable to Boolean

It is easy to convert anything a boolean in JavaScript. Truthy values will be converted to true and falsy values will be converted to false. There are 2 ways to convert variables to a boolean. There is the Boolean function, and there is the !! shortcut.

There are 6 kinds of falsy values:

  • false
  • 0
  • empty string: "" , '' , or ``
  • null
  • undefined
  • NaN — not a number value

Anything else is truthy.

If you evaluate them as boolean like so, you get:

Boolean(false); // false
Boolean(0); // false
Boolean(""); // false
Boolean(''); // false
Boolean(``); // false
Boolean(undefined); // false
Boolean(null); // false
Boolean(NaN); // false

as opposed to truthy values like objects, which are anything else but the values above:

Boolean({}) // true
Boolean(true) // true
Boolean([]) // true

You can also use the !! shortcut to cast to Boolean, the right ! cast the variable into a boolean and negate the value, and the left ! negate it back to the actual boolean value.

!!(false); // false
!!(0); // false
!!(""); // false
!!(''); // false
!!(``); // false
!!(undefined); // false
!!(null); // false
!!(NaN); // false

Similarly for truthy values:

!!({}) // true
!!(true) // true
!!([]) // true

With shortcut evaluation, boolean ANDs and ORs are evaluated up to the first truthy value:

const abc = false && "abc"; // false, since false is false and "abc" is trueconst def = false || "def"; // true, since false is false and "def" is true
Categories
JavaScript

Introduction to JavaScript Event Handlers

Any websites with dynamic functionality need to deal with users interacting with them. This is the pages have controls that users can use. To let users use those controls, the pages have to be able to handle the actions done by the users to the controls. These are example of events in JavaScript. Events also include other activities done by the browser like page loading.

With the HTML DOM, JavaScript can get the elements from there and handle events. Some events are divided into groups to what elements they’re applied to. Other events apply to all elements other than the body and frameset elements.

The list of events that are supported by all HTML elements are below:

  • abort, triggered when file load is aborted
  • change, triggered when value has changed
  • click, triggered when mouse is clicked or screen is tapped
  • dbclick, triggered when mouse is clicked twice
  • input , trigger when input value in an input or textarea element is changed
  • keydown, triggered when key is down
  • keyup, trigger when key is released after being pressed
  • mousedown, triggered when mouse button is down
  • mouseenter, triggered when mouse button is released
  • mouseleave, triggered when mouse leaves over an element
  • mousemove, triggered when mouse moves over an element
  • mouseout, triggered when mouse moves off an element
  • mouseover, triggered when mouse hovers over an element
  • mouseup, triggered when mouse button is released
  • mousewheel, triggered when mouse wheel is rotated
  • onreset , triggered when a form is reset
  • select, triggered when text is selected
  • submit, triggered when form is submitted
  • drag, triggered when element is being dragged
  • dragend, triggered when element is dragged
  • dragenter, triggered when dragged element enters the drop target
  • dragstart, triggered when element starts dragging
  • dragleave, triggered when dragged element leaves a valid drop target
  • dragover, triggered when element or text selection is dragged over a valid drop target
  • drop, triggered when element is dropped on a valid drop target

Below some HTML audio and video events:

  • pause, triggered when playback of media has started
  • play, triggered when playback has begun
  • playing, triggered when media is playing
  • seeking, triggered when media is being seeked
  • seeked, triggered when media is done seeking

Events supported by every element except the body and frameset elements are below:

  • blur, triggered when element loses focus
  • error, triggered when file failed to load
  • focus, triggered when element is in focus
  • load, triggered when a file and attached files are loading
  • resize, triggered when document is resized
  • scroll, triggered when element is scrolled

Events supported by the window object is below:

  • afterprint, triggered when print preview window has closed or document has started printing
  • beforeprint, triggered when print preview window is opened or document is going to print
  • beforeunload, triggered when the document is unloaded
  • hashchange, triggered when the part of the URL with the pound sign (#) is changed
  • pagehide, triggered when browser leaves a page in browser history
  • pageshow, triggered when browser goes to a page
  • popstate, triggered when session history item changes
  • unload, triggered when document and included files are being unloaded

There are many more events that can be handled by browsers. They are listed at https://developer.mozilla.org/en-US/docs/Web/Events.

Event Handling

When the browser’s JavaScript code is responding to those events, it’s called event handling. There are a few ways to handle events in JavaScript.

Inline Event Handlers

We can add event handlers straight to an element’s code. We can write code in HTML element’s attributes to handle code. For example, if we want to handle the event when a button is clicked we can put the event handling code in the onclick attribute of the button element, like so:

<button onclick='alert('Button clicked')>Click me</button>

It’s likely than we want to prevent the default action from happening, like navigating to a new page or triggering submit when a button is clicked. To prevent these default actions from happening, we can put return false at the end of the script. We can do following to prevent navigation to a new page if we handle the onclick event in an a tag:

<a onclick='alert('Clicked'); return false;'>Click me</a>

Handling Events in Script Tag

Inline event handlers aren’t good because you’re mixing dynamic code in HTML, which is supposed to only care about organizing pages into meaningful sections. Also, if you have complex code, then it’s very hard to put all the code in the attribute. We should attach event handlers to elements by getting them in dedicated code and then putting the code in the event handler’s callback function to handle the events.

For example, if we have code that increases and decrease the counter when you press different buttons, we can write the code as follows.

We make a new folder, then in index.html , we put:

<html>  
  <head>  
    <title>Counting App</title>  
  </head> 
  <body>  
    <h1>Click the button to count.</h1>  
    <p>Current Number: <span id="currentCount">0</span></p>  
    <button id="increaseButton">Increase</button>  
    <button id="decreaseButton">Decrease</button>  
    <script src="script.js"></script>  
  </body>  
</html>

Then in script.js , we put:

const handleIncrease = () => {  
  const currentCount = document.getElementById("currentCount");  
  const increaseButton = document.getElementById("increaseButton");  
  increaseButton.onclick = () => {  
    currentCount.innerHTML++;  
  };  
};

const handleDecrease = () => {  
  const currentCount = document.getElementById("currentCount");  
  const decreaseButton = document.getElementById("decreaseButton");  
  decreaseButton.onclick = () => {  
    currentCount.innerHTML--;  
  };  
};

const initialize = () => {  
  handleIncrease();  
  handleDecrease();  
};

window.onload = initialize;

In script.js, we have the functions to handle the clicks of the buttons in index.html. We attached the event handlers by getting the element object by using getElementById, then we set the onclick property of the elements with their own anonymous event handler functions. If we want to assign a function reference to it, we can do it like we did to window.onload. In the handlers we get the content of the element with IDcurrentCount, and then modified the innerHTML property to change the content after we got the original content. In the last line, we assign the initialize variable to it. We do not want to call it immediately, but rather when the event actually happened, so there’s no parenthesis after the initialize. We are assigning it the reference on the function, rather than calling it immediately and returning something then assigning the result to it.

addEventListener

Another way to attach an event handler to a function is to use the addEventListener function available with the HTML element object. The addEventListener event listens to DOM events that’s trigger and runs the callback function that you pass into it when the event happens. The callback function has one argument which contains the details of the event that was triggered. With addEventListener we can reuse code since we can use the same callback function in multiple places. You can also control how the event is triggered since we have the parameter which contains the event details. It also works on non-element nodes in the DOM tree.

If we change the above example to use addEventListener we can replace what we had in script.js with:

const handleClick = e => {  
  const currentCount = document.getElementById("currentCount");  
  if (e.target.id === "increaseButton") {  
    currentCount.innerHTML++;  
  } if (e.target.id === "decreaseButton") {  
    currentCount.innerHTML--;  
  }  
};

const handleIncrease = () => {  
  const increaseButton = document.getElementById("increaseButton");  
  increaseButton.addEventListener("click", handleClick);  
};

const handleDecrease = () => {  
  const decreaseButton = document.getElementById("decreaseButton");  
  decreaseButton.addEventListener("click", handleClick);  
};

const initialize = () => {  
  handleIncrease();  
  handleDecrease();  
};

window.onload = initialize;

As we can see, we used the same handleClick function for handling clicks of button the increaseButton and the decreaseButton. We did this by checking which element is triggering the click event by using the e.target.id property, which has the ID attribute of the element. Doing different actions in the same event handler function for different elements is called event delegation. We are delegating different actions as different elements are triggered. There’s less repeated code than the first example.

The addEventListener function takes 3 arguments. The first is the string that has the event name, the second is a callback function to handle the events. The last one indicates whether a parent element is also associated with the event. It’s true if it is and false otherwise.

If there’s a parent element that’s also associated with the event, then you can propagate the event to the parent element. It’s called bubbling up an event and the event will also be triggered on the parent element if it does. There’s also the capture method, which lets the parent element’s event happen first and the child after. It’s rarely used in code so we don’t have to be too concerned about this.

An example of event bubbling up would be as follows. If we have the following in index.html :

<html>  
  <head>  
    <title>Click App</title>  
  </head> 
  <body>  
    <div id="grandparent">  
      <div id="parent">  
        <button id="child">  
          Click Me  
        </button>  
      </div>  
    </div>  
    <script src="script.js"></script>  
  </body>  
</html>

and the following in script.js :

window.onload = () => {  
  const child = document.getElementById("child");  
  const parent = document.getElementById("parent");  
  const grandparent = document.getElementById("grandparent");  
  child.addEventListener(  
    "click",  
    () => {  
      alert("Child Clicked");  
    },  
    true  
  ); 

  parent.addEventListener(  
    "click",  
    () => {  
      alert("Parent Clicked");  
    },  
    true  
  ); 

  grandparent.addEventListener(  
    "click",  
    () => {  
      alert("Grandparent Clicked");  
    },  
    true  
  );  
};

Then when the button ‘Click me’ is clicked, we should get 3 alerts, since we specified to let the click events bubble up all the way to the top element.

Stop Event Propagation

If we only want the event to happen on the one you want, then you have to stop it from propagating to the parent. If we modify script.js from the previous example to:

window.onload = () => {  
  const child = document.getElementById("child");  
  const parent = document.getElementById("parent");  
  const grandparent = document.getElementById("grandparent");  
  child.addEventListener(  
    "click",  
    e => {  
      if (e.stopPropagation) {  
        e.stopPropagation();  
      }  
      alert("Child Clicked");  
    },  
    true  
  ); 

  parent.addEventListener(  
    "click",  
    e => {  
      if (e.stopPropagation) {  
        e.stopPropagation();  
      }  
      alert("Parent Clicked");  
    },  
    true  
  ); 

  grandparent.addEventListener(  
    "click",  
    e => {  
      if (e.stopPropagation) {  
        e.stopPropagation();  
      }  
      alert("Grandparent Clicked");  
    },  
    true  
  );  
};

We should only see ‘Grandparent Clicked’ since we stopped the event from propagating with the stopPropagation function. Stopping propagation should make your code faster since bubbling and capturing takes resources.

Categories
JavaScript JavaScript Basics

Adding Inputs and Outputs to JavaScript Apps

For many web apps, inputs and outputs are important parts of the app. Many parts of most applications consist of forms. JavaScript makes it easy to add forms and handle inputs and then get the outputs. An HTML form consists of many parts. It can have text inputs, text areas, checkboxes, radio buttons, dropdowns, buttons, etc. The look of them can be adjusted with CSS, and JavaScript lets you add dynamic functionality to the form.

The form element is the HTML element that contains the controls for forms. It holds all the text inputs, radio buttons, checkboxes, text areas, etc., along with the label text for each element. It can also contains HTML elements that divide the form into sections like div , article , and section elements.

To make a simple form, we can write the following:

<html>  
  <head>  
    <title>Form</title>  
  </head>  
  <body>  
    <form action="save.php" name="nameForm" method="post">  
      <label for="firstName">First Name: </label>  
      <input type="text" name="firstName" id="firstName" /><br />  
      <label for="lastName">Last Name: </label>  
      <input type="text" name="lastName" id="lastName" /><br />  
      <input type="submit" value="Submit" />  
    </form>  
  </body>  
</html>

In the example above, we have the action attribute in the form tag to tell the browser what to do with the form when the submit action is triggered. It can be sent to the server-side directly, or it can be manipulated on the client-side first before sending it to the server via Ajax. The name attribute is the name that the programmer assigns to the form. It’s a handy reference for accessing it in our JavaScript code. The method attribute is used when we send the form data to the server directly and it’s used to specify the HTTP method used to send the data to the server.

Other attributes that form elements can have include:

  • accept-charset: specifies the character set to use when sending the data to the server. It’s useful if your form inputs have multilingual content.
  • autocomplete: specifies whether the form should use browser’s autocomplete
  • enctype: indicates the type of content that’s sent to the server. If the data sent to the server is all text, then it should be text/html. If the form has file inputs, then it should be multipart/form-data. The default value is application/x-www-form-urlencoded .
  • novalidate: a boolean value that specifies whether we want to use browser’s form validation for form inputs
  • target: specifies whether we want the server’s response should be displayed after the form is submitted. The default setting is to open the response in the same browser window (value is _self ). If you want the response data to be shown in a new window, then it should be set to _blank.

Label Element

The label element is used to specify the text associated with a form field. It makes it clear to the user which field is used for entering what kind of data. It has a for attribute that takes the id of the input element as the value to associate the label with the form field. You can also nest the form field in the label element to associate the form field with the input element, so you don’t have to have an id attribute in your input field.

Input Element

Almost all forms have an input element. It’s used for entering text. Input elements have the type attribute which is usually set to text as the value. Other possible values include number , email , password , etc. The full list of types are listed below. Inputs also can have a value attribute which lets us set the value entered into the form field. It’s handy if you want to preset the value of the form field. The name attribute is also an important one since it lets us get the input by name and get the value from it.

Below is the full list of possible inputs that we can set in the type attribute:

  • button — a clickable button
  • checkbox — checkbox
  • color — color picker
  • date — date control
  • datetime — control to let us enter date and time (year, month, day, hour, minute, second, and a fraction of a second in UTC)
  • datetime-local — control to let us enter date and time (year, month, day, hour, minute, second, and a fraction of a second in local time)
  • email — email address
  • file — file upload
  • hidden — hidden input
  • image — submit button that has an image instead of text
  • month — month and year picker
  • number — input that only takes numbers
  • password — password field
  • radio — radio button
  • range — input that takes a range of numbers
  • reset — reset button
  • search — input that takes a search string
  • submit — submit button
  • tel — phone number input
  • text — a single line of text input. This is the default choice.
  • time — time input without taking into account the time zone
  • url — URL input
  • week — week and year input without taking into account the time zone

Select Element

The select element is a drop-down that lets users select from one or more choices in the drop-down list. We can also have default choices with the selected attribute and group the drop-down options with optgroup.

A simple example would be:

<select name='color'>  
  <option color='white'>White</option>  
  <option color='yellow'>Yellow</option>  
  <option color='black'>Black</option>  
</select>

If we want to group items together we can write:

<select name='car'>  
  <optgroup label="American Cars">  
    <option value="ford">Ford</option>  
    <option value="gm">GM</option>  
  </optgroup>  
  <optgroup label="Japanese Cars">  
    <option value="toyota">Toyota</option>  
    <option value="mazda">Mazda</option>  
  </optgroup>  
</select>

An option can have a selected attribute to make a choice a preset choice:

<select name='color'>  
  <option color='white' selected>White</option>  
  <option color='yellow'>Yellow</option>  
  <option color='black'>Black</option>  
</select>

Textarea

A textarea element is a multline text input field:

<textarea name='recipe' rows='10' cols='50'></textarea>

Button

We can use the button element to create our submit button instead of an input with type attribute set to submit . We can write:

<button type='submit'>Submit</button>

which is the same as:

<input type='submit value='Submit' >

The Form Object

The form object is an HTML DOM object that represents the form element that you defined in HTML. We can manipulate the form object to get the input and set different options to our liking, to change the behavior of the form. With the form object, we get full access to all parts of the form.

A form object has the following properties:

  • acceptCharset — get or set a list of character sets supported by the server
  • action — get or set the action attribute of the form
  • autocomplete — get or set whether to turn on or off autocomplete attribute of the form
  • encoding — set the enctype attribute of the form, or the way data is encoding when sending to the server
  • enctype — set the enctype attribute of the form, or the way data is encoding when sending to the server
  • length — get the number of controls in a form
  • method — get or set the HTTP method used to submit the form data
  • name — get or set the name attribute of the form
  • noValidate — get or set the novalidate attribute of the form, or whether validation can be skipped by the browser
  • target — indicate the place to show the response data after submitting a form

Autocomplete Attribute

The autocomplete attribute in a form tells the browser whether to use its autocomplete feature to let users enter data by getting existing input data that was saved from previous data entries. We can set it to form the whole form or just single inputs.

Getting Form and Input Attributes

We can get a form’s attribute like getting the attributes of any other element. So we can use getElementById , getElementsByTagName , querySelector , querySelectorAll , or getElementsByClassName to get what we want.

For example, we can use document.querySelector('form') to get the first element with the form tag, which is a convenient way of getting forms. If we have more than one form element in one page, then we can get it by using document.querySelector('form')[0] to get the first one, document.querySelector('form')[1] to get the second one, etc.

Also, there is the document.forms property, which we can use to access a form if the form has a name attribute. If it has a name attribute, then we can pass it in as the key. For example, if there’s a form with name attribute set to nameForm , then we can write document.forms.nameForm or document.forms['nameForm'] to get the form.

A form object has a methods, reset() and submit() . The reset method clears the input values and reset all validation previously done to the form. It’s the same as having a input with type reset in the form, which also clears the form’s inputs, like the following:

<input type='reset' value='Clear form'>

The submit method submits the form data to the place you want depending on the action, method and target attributes. It’s the same as what an input element with type submit does, like the following:

<input type='submit' value='Submit'>

We have the example below for making a form that displays an alert of the inputted values after the Submit button is clicked. In index.html, we add our form by adding the following:

<html>  
  <head>  
    <title>Form</title>  
  </head>  
  <body>  
    <form action="" name="nameForm" method="post">  
      <label for="firstName">First Name: </label>  
      <input type="text" name="firstName" id="firstName" /><br />  
      <label for="lastName">Last Name: </label>  
      <input type="text" name="lastName" id="lastName" /><br />  
      <input type="submit" value="Submit" />  
    </form>  
    <script src="script.js"></script>  
  </body>  
</html>

Then in script.js , we add:

window.onload = () => {  
  const nameForm = document.forms.nameForm;  
  nameForm.method = "post";  
  nameForm.target = "_blank";  
  nameForm.action = "";  
  nameForm.addEventListener("submit", e => {  
    e.preventDefault();  
    const firstName = document.getElementById("firstName");  
    const lastName = document.getElementById("lastName");  
    alert(`Your name is ${firstName.value} ${lastName.value}`);  
  });  
};

We use the document.forms property to get the form with name attribute set to nameForm in the script. Then we set the method , target , and action properties. We do not want to submit to a server immediately, so in the handler function that we pass into the addEventListener function, we add e.preventDefault() to prevent the submit action. Then we get the values of the firstName and lastName field and display an alert from it.

Other ways to get input fields in a form element in this example is to use nameForm.firstName instead of document.getElementById(“firstName”), or set an ID for the form and then get the form element by ID then access the form field with the given name as a property of the form object. So if we have:

<html>  
  <head>  
    <title>Form</title>  
  </head>  
  <body>  
    <form action="" name="nameForm" id="nameForm" method="post">  
      <label for="firstName">First Name: </label>  
      <input type="text" name="firstName" id="firstName" /><br />  
      <label for="lastName">Last Name: </label>  
      <input type="text" name="lastName" id="lastName" /><br />  
      <input type="submit" value="Submit" />  
    </form>  
    <script src="script.js"></script>  
  </body>  
</html>

in index.html , then in script.js , we can write:

document.getElementById("nameForm").firstName

to get the first name field instead of what we have above.

Setting Form Values

We can set form values with the value property of an input element. We can access the form elements like we did before, and set the value attribute of a form element. For example, if we have index.html with the following code:

<html>  
  <head>  
    <title>Form</title>  
  </head>  
  <body>  
    <form action="" name="nameForm" id="nameForm" method="post">  
      <label for="firstName">First Name: </label>  
      <input type="text" name="firstName" id="firstName" /><br />  
      <label for="lastName">Last Name: </label>  
      <input type="text" name="lastName" id="lastName" /><br />  
      <input type="submit" value="Submit" />  
    </form>  
    <script src="script.js"></script>  
  </body>  
</html>

and script.js with:

window.onload = () => {  
  const nameForm = document.forms.nameForm;  
  nameForm.method = "post";  
  nameForm.target = "_blank";  
  nameForm.action = "";  
  const firstName = document.getElementById("firstName");  
  const lastName = document.getElementById("lastName");  
  firstName.value = "John";  
  lastName.value = "Smith"; nameForm.addEventListener("submit", e => {  
    e.preventDefault();  
    alert(`Your name is ${firstName.value} ${lastName.value}`);  
  });  
};

Then we set the default value of firstName and lastName fields by setting the value property of both field objects when the page is loaded.

Form Validation

Most forms need to be validated for valid data before submitting the form data to ensure that we don’t get bad data. With JavaScript, we can use regular expressions to validate the content of each input to ensure that they’re entered in the correct format. We can extend the examples above to include form validation. HTML5 also provides attributes to validate form data in HTML instead of JavaScript. However, if you want to customize your validation, then JavaScript makes this possible.

To validate forms with JavaScript, we can do the following. In index.html, we put:

<html>  
  <head>  
    <title>Form</title>  
  </head>  
  <body>  
    <form action="" name="nameForm" id="nameForm" method="post">  
      <label for="firstName">First Name: </label>  
      <input type="text" name="firstName" id="firstName" /><br />  
      <label for="lastName">Last Name: </label>  
      <input type="text" name="lastName" id="lastName" /><br />  
      <label for="email">Email: </label>  
      <input type="text" name="email" id="email" /><br />  
      <input type="submit" value="Submit" />  
    </form>  
    <script src="script.js"></script>  
  </body>  
</html>

Then in script.js , we add:

window.onload = () => {  
  const nameForm = document.forms.nameForm;  
  nameForm.method = "post";  
  nameForm.target = "\_blank";  
  nameForm.action = "";  
  nameForm.addEventListener("submit", e => {  
    e.preventDefault();  
    const firstName = document.getElementById("firstName");  
    const lastName = document.getElementById("lastName");  
    const email = document.getElementById("email");  
    let errors = [];  
    if (!firstName.value) {  
      errors.push("First name is required.");  
    } 

    if (!lastName.value) {  
      errors.push("Last name is required.");  
    } 

    if (!email.value) {  
      errors.push("Email is required.");  
    } 

    if (!/\[^@\]+@\[^\.\]+\..+/.test(email.value)) {  
      errors.push("Email is invalid.");  
    } 

    if (errors.length > 0) {  
      alert(errors.join(" "));  
      return;  
    }  
    alert(  
      `Your name is ${firstName.value} ${lastName.value}. Your email is ${email.value}`  
    );  
  });  
};

In the example above, we check each field’s value to see if they’re filled in. Then for the email field, we check if the field is filled in and that it matches the email format with a regular expression check. To learn more about regular expressions, you can go to https://regexone.com/. The regular expression we have basically checks if we have characters before the at sign, then the at sign, then check if we have anything separated by a dot after the at sign.

If there are errors, we display an alert box with all the errors. Otherwise, we show what’s entered.

If we want to use HTML for validation, we can do the following instead. In index.html, we put:

<html>  
  <head>  
    <title>Form</title>  
  </head>  
  <body>  
    <form action="" name="nameForm" id="nameForm" method="post">  
      <label for="firstName">First Name: </label>  
      <input type="text" name="firstName" id="firstName" required /><br />  
      <label for="lastName">Last Name: </label>  
      <input type="text" name="lastName" id="lastName" required /><br />  
      <label for="email">Email: </label>  
      <input type="text" name="email" id="email" /><br />  
      <input type="submit" value="Submit" />  
    </form>  
    <script src="script.js"></script>  
  </body>  
</html>

Then in script.js , we put:

window.onload = () => {  
  const nameForm = document.forms.nameForm;  
  nameForm.method = "post";  
  nameForm.target = "_blank";  
  nameForm.action = "";  
  nameForm.addEventListener("submit", e => {  
    e.preventDefault();  
    const firstName = document.getElementById("firstName");  
    const lastName = document.getElementById("lastName");  
    const email = document.getElementById("email");  
    alert(  
      `Your name is ${firstName.value} ${lastName.value}. Your email is ${email.value}`  
    );  
  });  
};

We’ve put validation attributes in the input elements like required and pattern in the HTML form instead of using JavaScript to validate the data. They serve the same purpose since the browser prevents you from submitting the form if there’re invalid values in any input, so the submit event is only triggered if everything’s valid. The only difference is that the validation messages are controlled by the browser so there’s less choice in controlling how it’s displayed.

Now that we know how to add forms to a web page with form validation, we can make many features of a web app. For many web apps, inputs and outputs are important parts of the app. Many parts of most applications consist of forms.