Categories
Object-Oriented JavaScript

Object-Oriented JavaScript — Events

JavaScript is partly an object-oriented language.

To learn JavaScript, we got to learn the object-oriented parts of JavaScript.

In this article, we’ll look at listening to events.

Events

We can listen to events triggered by users.

For instance, we can listen to mouse button clicks, keypresses, page load etc.

We can attach event listener functions to listen to all these events.

Inline HTML Attributes

One way to add event listeners to our elements is to add them as attribute values.

For instance, we can write:

<div onclick="alert('clicked')">click me</div>

We have the onclick attribute with value being the JavaScript code alert(‘clicked’) .

This is easy to add, but hard to work with if the code gets complex.

Element Properties

We can also add them as element properties.

For instance, given the following HTML:

<div>click me</div>

We can write:

const div = document.querySelector('div');
div.onclick = () => {
  alert('clicked');
};

We have the div which we get with document.querySelector .

Then we set the onclick property to a function that runs when we click on the div.

This is better because it keeps JavaScript out of our HTML.

The drawback of this method is that we can only attach one function to the event.

DOM Event Listeners

The best way to listen to browser events is to add event listeners.

We can have as many as of them as we want.

And the listeners don’t need to know about each other and can work independently.

To attach an event listener to our element, we can call the addEventListener method.

For instance, we can write:

const div = document.querySelector('div');
div.addEventListener('click', () => {
  alert('clicked');
});

div.addEventListener('click', console.log.bind(div))

We added 2 different event listeners.

One is a function to display an alert.

The other is to log the event object in the console.

Capturing and Bubbling

The addEventListener method takes a 3rd parameter.

It lets us set whether to listen in capture mode or not.

Event capturing is when an event propagates down from the document object to the element which originally triggered the event.

Event bubbling is the opposite. It’s where an event propagates from element that triggered the event to the document object.

If we set the 3rd parameter to true , then we listen to the event propagation from the docuemnt object to the original element.

An event goes from the capture phase to the originating element, to the bubbling phase.

Most browsers implement all 3 phases, so we can set the optional anywhere.

We can stop the propagation from the originating element to the document by calling stopPropagation on the event object.

We can also use event delegation to check which element triggered an event.

Conclusion

There are a few ways to listen to events from elements.

We can add event listeners or add inline JavaScript to HTML.

Categories
Object-Oriented JavaScript

Object-Oriented JavaScript — Event Handling

JavaScript is partly an object-oriented language.

To learn JavaScript, we got to learn the object-oriented parts of JavaScript.

In this article, we’ll look at event handling.

Stop Propagation

We can stop events from bubbling up with the stopPropagation method.

If we don’t want events to propagate from the element where the event originated to the document and everything in between, we can write:

const div = document.querySelector('div');
div.addEventListener('click', (e) => {
  e.stopPropagation();
  alert('clicked');
});

e is the event object.

And we can call stopProgation on it so that only the listener for the div will listen to the click event.

Prevent Default Behavior

We can prevent the default behavior of the browser by calling the preventDefault method on it.

For example, if we have the following HTML:

<a href='http://example.com'>click me</a>

We can listen to the click event by writing:

const a = document.querySelector('a');
a.addEventListener('click', (e) => {
  if (!confirm('You sure you want to leave?')) {
    e.preventDefault();
  }

});

We have a confirm function call to show a dialog.

If the user clicks Cancel, then the function returns false and preventDefault will be called.

Once that’s done, then the default action for the a element, which is the go to the URL in the href attribute, will be stopped.

Not all events let us prevent the default behavior, but most do.

If we want to be sure, we can check the cancellable property of the event object.

Cross-Browser Event Listeners

Most modern browsers implement the DOM 2 spec, so the code that we write is mostly compatible with them.

The only difference is in IE, which is being phased out quickly.

Types of Events

There are different kinds of events that can be emitted.

They include mouse events like mousemove, mouseup , mousdown , click , and dblclick .

mouseover is emitted when the user puts the mouse over an element.

mouseout is emitted when the mouse was over an element but left it.

Keyword events include keydown , keypress , and keuyup .

These occur in sequence.

Loading and window events include the load event, which is emitted when an image or a page and all its components are done loading.

unload is emitted when the user leaves the page.

beforeunload us loaded before the user leaves the page.

error is emitted when there’s a JavaScript error.

resize is emitted when the browser is resized.

scroll is emitted when the page is scrolled.

contextmenu is emitted when the right-click menu appears.

Form events include focus when we enter a form field.

blur is emitted when we leave a form field.

change is emitted when we leave a field after the value has changed.

select is emitted when we select a text field.

reset is emitted when we wipe out all inputs and submit is emitted when we send the form.

Modern browsers also have drag events like dragstart , dragend , drop , etc.

Conclusion

We can stop propagation or the default behavior of events.

Also, we can listen to various kinds of events.

Categories
Object-Oriented JavaScript

Object-Oriented JavaScript — Async Scripts and Namespacing

JavaScript is partly an object-oriented language.

To learn JavaScript, we got to learn the object-oriented parts of JavaScript.

In this article, we’ll look at some basic coding and design patterns.

Async JavaScript Loading

By default, script tags are loading synchronously.

This means they’re loading in the order that they’re added in the code.

Therefore, we can move our script tags to the bottom of the page so that we see the HTML content first.

HTML5 has the defer attribute to let us load scripts asynchronously but in the order that they’re added in.

For instance, we can write:

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

We just add the defer attribute to the bottom of the script.

This isn’t supported by older browsers, but we can do the same thing by loading our scripts with JavaScript.

For instance, we can write:

<script>
  (function() {
    const s = document.createElement('script');
    s.src = 'script.js';
    document.getElementsByTagName('head')[0].appendChild(s);
  }());

</script>

We create a script element, set the src value to the script path and attach it as a child of the head tag.

Namespaces

We can add an object to namespace our app.

This way, we won’t have so many global variables in our app.

For instance, we can write:

let APP = APP || {};

to create a MYAPP namespace.

Then we can add properties to it by writing:

APP.event = {};

And then we can add properties to the event property:

APP.event = {
  addListener(el, type, fn) {
    // ..
  },
  removeListener(el, type, fn) {
    // ...
  },
  getEvent(e) {
    // ...
  }
  // ...
};

Namespaced Constructors

We can put constructors inside our namespace object.

For instance, we can write:

APP.dom = {};
APP.dom.Element = function(type, properties) {
  const tmp = document.createElement(type);
  //...
  return tmp;
};

We have the Element constructor to create some object with.

A namespace() Method

We can create a namespace method to let us create our namespace dynamically.

For instance, we can write:

APP.namespace = (name) => {
  const parts = name.split('.');
  let current = APP;
  for (const part of parts) {
    if (!current[part]) {
      current[part] = {};
    }
    current = current[part];
  }
};

We create a namespace method that takes a string with words separated by dots.

Then we add the properties to the current object by looping through them.

Once we defined it, we can use it by writing:

APP.namespace('foo.bar.baz');

console.log(APP);

We see the foo.bar.baz property in the console log.

Init-Time Branching

Different browsers may have different functions that implement the same functionality.

We can check for them and add the functionality we want by checking and which one exists and then add the one that exists to our namespace object.

For instance, we can write:

let APP = {};

if (window.addEventListener) {
  APP.event.addListener = function(el, type, fn) {
    el.addEventListener(type, fn, false);
  };
  APP.event.removeListener = function(el, type, fn) {
    el.removeEventListener(type, fn, false);
  };
} else if (document.attachEvent) {
  APP.event.addListener = function(el, type, fn) {
    el.attachEvent(`on${type}`, fn);
  };
  APP.event.removeListener = function(el, type, fn) {
    el.detachEvent(`on${type}`, fn);
  };
} else {
  APP.event.addListener = function(el, type, fn) {
    el[`on${type}`] = fn;
  };
  APP.event.removeListener = function(el, type) {
    el[`on${type}`] = null;
  };
}

We check for different versions of the addEventListener and removeEventListener and their equivalents and put them one that exists in our namespace.

This puts all the feature detection code in one place so we don’t have to that multiple times.

Conclusion

We can create namespace objects to keep our code away from the global namespace.

JavaScript scripts can be loaded asynchronously.

Categories
Object-Oriented JavaScript

Object-Oriented JavaScript — Timers and the DOM

JavaScript is partly an object-oriented language.

To learn JavaScript, we got to learn the object-oriented parts of JavaScript.

In this article, we’ll look at the built-in properties of window and the DOM.

The window.setTimeout() and window.setInterval() Methods

We can use the window.setTimeout and window.setInterval methods to schedule the execution of some JavaScript code.

setTimeout lets us run some code after a delay.

For instance, we can write:

function foo() {  
  alert('foo');  
}  
setTimeout(foo, 2000);

It returns the ID of the timer.

We can use the ID to call clearTimeout to cancel the timer.

For example, we can write:

function foo() {  
  alert('foo');  
}  
const id = setTimeout(foo, 2000);  
clearTimeout(id);

then the alert will never be shown because clearTimeout before the 2 seconds are up.

We can use the setInterval method to schedule foo to run every 2 seconds.

For instance, we can write:

function foo() {  
  console.log('foo');  
}  
const id = setInterval(foo, 2000);

We can call clearInterval to cancel the timer by writing:

clearInterval(id);

Scheduling a function in some amount of milliseconds isn’t a guarantee that it’ll execute exactly at that time.

Most browsers don’t have millisecond resolution time.

Also, the browser maintains a queue of what we expect them to do.

100ms means adding to the queue after 100 ms.

But the queue may be delayed by something slow.

Most recent browsers have the requestAnimationFrame function which is better than timeout functions because we ask the browser to run or function whenever it has the resources.

The schedule isn’t defined in milliseconds.

For instance, we can write:

function animateDate() {  
  requestAnimationFrame(() => {  
    console.log(new Date());  
    animateDate();  
  });  
}  
animateDate();

to log the latest date whenever the browser can run the code.

The window.document Property

The window.document property is a BOM object that refers to the currently loaded document or page.

DOM

The DOM represents an XML or an HTML document as a tree of nodes.

We can use DOM methods and properties to access any element on the page.

Also, we can use them to modify or remove elements.

It’s a language-independent API that can be implemented in any language.

We can view the DOM tree within the Elements tab of the browser.

For example, we should see that a p element is created by the HTMLParagraphElement constructor.

And the head tag is created by the HTMLHeadElement constructor.

Core DOM and HTML DOM

The core DOM forms the most basic parts of the DOM specification.

And the HTML DOM specification builds on top of the core DOM.

The following constructors are in the core DOM:

  • Node — any node on the tree
  • Document — the document object
  • Element — tags in the tree
  • CharacterData — constructor for dealing with texts
  • Text — text node in a tag
  • Comment — a comment in the document
  • Attr — an attribute of a tag
  • NodeList — list of nodes, which is an array-like object with a length property
  • NamedNodeMap — same as NodeList but the nodes can be accessed by name rather than numeric index.

The HTML DOM has the following constructors:

  • HTMLDocument — an HTML specific version of the document object
  • HTMLElement — parent constructor of all HTML elements
  • HTMLBodyElement — element representing the body tag
  • HTMLLinkElement — an a element
  • HTMLCollection — a NamedNodeMap that’s specific to HTML

We can use them to access DOM nodes, and modify, create, and remove nodes.

Conclusion

An HTML document is represented by the DOM.

We can get and manipulate the nodes in the DOM tree to do what we want.

window has timer methods to let us schedule code to run.

Categories
Object-Oriented JavaScript

Object-Oriented JavaScript — Styles and Nodes

JavaScript is partly an object-oriented language.

To learn JavaScript, we got to learn the object-oriented parts of JavaScript.

In this article, we’ll look at the DOM and inserting and copying nodes.

Modifying Styles

We can change the styles of an element.

For instance, we can write:

const p = document.getElementById('closer');
p.style.border = "1px solid green";

then we set the border of the p element to green.

We can also set the font-weight with the fontWeight property:

p.style.fontWeight = 'bold';

We can set styles with the cssText property:

p.style.cssText; "border: 1px solid green; font-weight: bold;"

The styles can be changed with some string manipulating:

p.style.cssText += " border-style: dashed";

Forms

We can manipulate forms by getting the form element.

For example, we can write:

const input = document.querySelector('input[type=text]');

to get the first input with type attribute set to text.

Then we can get the name property with input.name .

We can set the value entered into the box with:

input.value = 'abc';

And we can get the button for the form with:

document.querySelector("button")

Creating New Nodes

We can create new nodes with the createElement method.

For example, we can write:

const p = document.createElement('p');
p.innerHTML = 'foo';

to create a p element with content 'foo' .

We can get the style with the style property:

p.style

And we can assign new styles to it:

p.style.border = '2px dotted green';

Then we can attach it to a node like the body:

document.body.appendChild(p);

appendChild attaches the node as the last child node of body.

DOM-Only Method

We can also use DOM methods to add text nodes and styling.

For instance, we can use createTextNode to create the text node:

const p = document.createElement('p');
const text = document.createTextNode('something'); p.appendChild(text);

We created a p element and attached the text node 'something' to it.

We can also call appendChild with a text node to add it as a child node:

const str = document.createElement('strong');
str.appendChild(document.createTextNode('bold'));

We created a strong element and added the text bold to it,

The cloneNode() Method

We can clone a node with the cloneNode method.

For instance, we can write:

const el = document.querySelector('p');
document.body.appendChild(el.cloneNode(false));

We get a p element, cloned it with cloneNode , and then attached it to the body.

A shallow copy is done without any children. The false argument will make the copy shallow.

To make a deep copy with all the child nodes copied, we can change the argument of cloneNode to true :

const el = document.querySelector('p');
document.body.appendChild(el.cloneNode(true));

The insertBefore() Method

We can use the insertBefore method to add a child node before a given node.

For instance, we can write:

document.body.insertBefore(
  document.createTextNode('first node'),
  document.body.firstChild
);

We called inserBefore to insert a text node before the first child of the body .

Conclusion

We can add and remove nodes with various methods.

Their styles can be changed with the style property.