Categories
Object-Oriented JavaScript

Object-Oriented JavaScript — Separating Behavior

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.

Coding and Design Patterns

To organize our code in ways that we can work with them easily, we got to follow some patterns that allow that to happen.

Many people have thought of this problem, so we can follow existing patterns mostly.

Coding patterns are some best practices we can follow to improve our code.

Design patterns are language-independent patterns that are popularized by the Gang of Four book.

Separating Behavior

The building blocks of a web page includes HTML, CSS, and JavaScript code.

The content should be in the HTML code.

They have the markup to describe the meaning of the content.

For instance, we use ul for lists and li for list items and so on.

HTML code should be free from any formatting elements.

Visual formatting belongs to the presentation layer and should be achieved with CSS.

The style attribute shouldn’t be used for formatting.

Presentational HTML tags also shouldn’t be used.

Tags should be used form their meaning.

So section for dividing the text into sections, aside for a sidebar etc. should be used instead of div for everything.

Presentation

To make our pages presentable we can reset the browser defaults to be the same across all browsers.

Popular CSS frameworks like Bootstrap will do this.

Behavior

Any dynamic behavior should be written in the JavaScript code.

The JavaScript should be in scripts that are in external files in script tags.Inline attributes like onclick , onmouseover , etc. shouldn’t be used.

We should minimize the number of script tags so less JavaScript code has to be loaded.

Inline event handlers should be avoided to keep JavaScript code outside of HTML code.

CSS expressions shouldn’t ve used to keep compatibility.

To separate behavior, we can separate our form submission code from the form itself.

For example, we can write the following HTML:

<body>
  <form id="nameForm" method="post" action="server.php">
    <fieldset>
      <legend>name</legend>
      <input name="name" id="name" type="text" />
      <input type="submit" />
    </fieldset>
  </form>
  <script src="script.js"></script>
</body>

to create a form.

Then we can listen to the submit event in script.js :

const nameForm = document.querySelector('#nameForm');
nameForm.addEventListener('submit', (e) => {
  const el = document.getElementById('name');
  if (!el.value) {
    e.preventDefault();
    alert('Please enter a name');
  }
});

We get the form with querySelector .

Then we listen to the submit event with addEventListener .

In the event handler, we get the name field by its ID.

If there’s no value, we stop the submission with preventDefault() .

And then we display an alert.

Conclusion

We should separate content, styling, and dynamic behavior in our code.

Categories
Object-Oriented JavaScript

Object-Oriented JavaScript — Removing Nodes and Document

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 some useful document properties.

Removing Nodes

We can call the removeChild method to remove a child node.

For instance, if we have the following HTML:

<body>
  <p class="opener">foo</p>
  <p><em>bar</em> </p>
  <p id="closer">baz</p>
  <!-- the end -->
</body>

We can remove the node by writing:

const p = document.querySelector('p');
const removed = document.body.removeChild(p);

then the p element is removed from the body with removeChild .

The removed node is returned.

There’s also the replaceChild method that lets us remove a node and puts another one in place.

For example, we can write:

const p1 = document.querySelector('.opener');
const p2 = document.querySelector('#closer');
const removed = document.body.replaceChild(p1, p2);

to replace the node with ID closer with the one that has class opener .

HTML — only DOM Objects

There are various ways to access HTML-only DOM objects.

We can access than with some properties that are available in modern browsers.

document.body has the body element.

It’s one of the elements that are in the DOM Level 0 spec that’s moved to the HTML extension of the DOM spec.

Other properties includes the document.images to get the img elements.

document.applets lets us get the applet elements.

document.links gets us the link elements.

document.anchors gets us anchor a elements.

document.forms lets us get the forms.

So:

document.forms[0];

is the same as:

document.getElementsByTagName('forms')[0];

If we have the following form:

<form>
  <input name="name" id="name" type="text" size="50" maxlength="255" value="Enter name" />
</form>

Then we can get the input element and set the value with:

document.forms[0].elements[0].value = 'foo';

We can disable the input with:

document.forms[0].elements[0].disabled = true;

And we can get the input by its name attribute with:

document.forms[0].elements['name'];

or:

document.forms[0].elements.name;

The document.write() Method

The document.write method lets us write HTML to the page.

For example, we can write:

document.write(`<p>${new Date()}</p>`);

to write the date to the screen.

If we load the page, document.write will replace all the content on the page.

Cookies, title, referrer, and domain

We can get and set the client-side cookies with the document.cookie property.

It’s a string that has some key-values and the expiry date.

When a server sends a page to the client, it may send the Set-Cookie HTTP response header back with the cookie.

The document.title property lets us get and set the title of the page, so we can write:

document.title = 'title';

The document.domain property has the domain of the current page.

We may get something like “jsfiddle.net” if we are in there.

We can’t set it to a different domain, so if we’re in jsfiddle.net, then we can’t write:

document.domain = 'example.com'

We’ll get the error:

Uncaught DOMException: Failed to set the 'domain' property on 'Document': 'example.com' is not a suffix of 'jsfiddle.net'.

This is good for protecting users. We don’t want to let scripts go to any domain they like.

Conclusion

We can remove nodes with DOM methods.

Also, we can use various properties and methods of document to manipulate a document.

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.