Client Side API
Last updated
Was this helpful?
Last updated
Was this helpful?
In this section, we will see the principal Web API client-side which are built-in the browsers. As a reminder, API (Application Programming Interfaces) are a way to simplify the construction of complex functionnalities by using abstract, high-level, functionnalities. The principal API we will use are the DOM API, used to manipulate the DOM for your page.
For your project, you will probably need the four following API:
DOM API
Fetching API
Drawing API
Audio API
Generally speaking, an API uses JavaScript object to handle the data from the API. This means that you can manipulate these objects in your code and access API's data easily by they properties and their methods. For example, retrieving a document on the page Object.getElementById(id)
or playing a sound SoundObject.play()
.
Most of API are events based, and handle events to change their inner state. Thus, they heavily rely on callback functions to behave correctly according to specific situation in your code (e.g. xmlHttpRequest
object). Check the Event section for more information about callbacks.
When manipulating an API, you should identify where its entry point(s) is(are). An entry point is generally an object representing the API's data, where most of the functionnalities of the API are available and where you can begin to work with.
Obviously, the entry point for the DOM API is the Document document
, or an instance of an HTML element that you want to affect in some way. For the 2D API Canvas
, its the <canvas>
element and then calling CanvasElement.getContext()
.
When you are learning a new API, check for its entry points first. They will help you to understand the "flow" of the API.
As you already know, the content you see in your browser is a set of HTML, CSS and JS. HTML is the content of your web page, and has a tree structure in order to be easier to be manipulate. This tree structure is called DOM.
In the above tree example, we can highlight important concepts:
Element node: It is an element as it exists in an HTML file (e.g. <p>
)
Root node: The top node in the tree, which is always HTML
for HTML file
Child node: The direct node of a chosed node
Descendant node: A node contained inside a chosed node, independantly of its depths
Parent node: The node of a descendant node
Sibling nodes: Nodes that are in the same level in the DOM tree
Text node: A node containing a text string
JavaScript has been made principally to manipulate the DOM of a page.
DOM elements retrieval is more than a common operation: it allows you to get the element to listen to, the element you want to update and so on. There is a lot of way for selecting DOM elements in JS. We will see the more common and convenient here.
Old selector functions are getElementByClass
and getElementById
. They select specific elements in the DOM according, respectively, to their class or their id. They are used with a direct reference with the document.
In more recent JavaScript version, querySelector
has been introduced. It is more powerfull and versatile than the getElementByXXX
since it combines all these functions in one. Concretly, querySelector
relies on CSS selector to perform the search in the DOM tree, somewhat unifying the selecting keywords in JS and CSS.
The above example can be written as follow using querySelector
Consequently, since you can use CSS selector in querySelector
, you can now make complex query (taken from MDN)
You can manually add (therefore creating) new elements to the DOM using JavaScript. To create programmatically a new HTML element, the keyword is createElement(ANY_HTML_ELMT)
, and it is used like that:
Now, we just need to attach this new paragraph to our document. Let's say that we want to attach it to the main div of our page, then we first need to select these div, and attach its the new paragraph.
Applying several time appendChild with the same object will not duplicate it in the reference node. If you need to duplicate an element, use the .cloneNode
method.
HTML element can have attributes (e.g. an id
, a src
). Since getting DOM elements returns us objects, we can directly access these attributes in their properties!
Sometimes, though, the attributes attached to an HTML element can be non-standard (i.e. either not expected for the element, or does not exist in the standard). For non-standard attributes, their corresponding properties are not created in the object!
However, you can access/modify/remove such non-standard attributes by using the following methods:
.hasAttribute(name)
.getAttribute(name)
.setAttribute(name, value)
.removeAttribute(name)
When a standard attribute changes, the change also reflects in the corresponding property. The other way is also true. So when you perform a elm.setAttribute("attr", value)
, the changed is reported back to the HTML element's attribute.
However, their is (ofc...) exceptions to this. For example, the input.value
synchronises itself only in the attribute -> propertye way, not the other. That means that you cannot perform a .setAttribute("value", "someVal")
on an input element.
Non-standard properties are usefull to pass some specific data to your HTML elements. However, since the HTML evolves continiously, it may happen that your non standard property becomes a standard property, possibly making huge mess in your code.
That is why to avoid conflict dataset has been introduced for the data-*
attributes. All HTML object has a dataset property listing all the data attributes an HTML element has.
All attributes starting with “data-” are reserved for programmers’ use. They are available in the dataset property.
For example, if your element has an data attribute named data-family
, you can access it:
Multiword attributes like data-my-family
become camel-cased: dataset.orderMyFamily
.
In addition, data attribute can even be used to store other object (use it with parsimony). Since they are HTML attributes however, we can't store an object reference directly, we have to transform it in a compatible string. That is good because an object can be encoded as a JSON object, so with can do the following:
It is also possible to manipulate the styles of your DOM elements! More information here.
In a web component paradigm (we will see that with Vue.js), an important aspect is the encapsulation of markup structure, styles and behaviors: they should nenot be leaking between components. However, due to how the DOM and the DOM API are made, this is not possible by simply using the standard DOM specification.
That is why the concept of Shadow DOM has been introduced. Shadow DOMs are hidden DOMs, not parsed by the DOM API, and only sensible to what happen inside them. We will cover this aspect in more detail in the Single Page Application section.
More information about shadow dom here.
Form and control elements are one of the principal source of interaction between your user and the server. That is why they have special properties and events attached to make their use more convenient in JavaScript.
Despite forms can be retrieved as any HTML elements using selector (e.g. querySelector
), they are also member of a special named (and ordered) property collection of the document
, called forms
. And, each form of this document.forms
collection has a named (and ordered) collection elements
, listing all the elements contained in the form. Therefore, you can then easily access any form and form's elements in a page simply by name.
No matter how a form element is deep in the form, it is listed in the elements
property of the form object.
If you organise your form with <fieldset>
element, you gain even more control on how your form is structured. Each fieldset
element also has an elements
property listing all its child form elements. And since a fieldset
is a form element, it is also retrievable by its name.
In case of Fieldset, that means your fieldset's elements exists both in the form.elements
and in the fieldset.elements
!
There is a backreferencing for each element of a form. That means you can get the form where the element belongs. Simply use the form
property of the form element.
Form control is related to accessing, setting and checking form's elements value. To access their value, we can use the value
property. Note that its content depends obviously of the type of input checked.
You can also set the element value.
Generally speaking, the information of interest in an element form is stored in the value
property, not in the innerHTML
.
So far, we have seen how to access forms' elements. However, this is not really useful if we did not know when to check for their value! Luckily, JavaScript trigger a lot of events when elements are used.
Every time an element's value is modified by the user, this event is triggered.
The input event does not only trigger with keyboard events, but also with other device, such as mouse (e.g. pasting a text from the clipboard) or with text recognition device. However, non altering action, such as pressing ^
alone (or directional arrow) does not trigger this event.
This event is good if you need a fine management on the element.
However, we often don't need such a fine management over an element. We prefer to check the element once it has lost focused. The event is change
and can be used as follow.
If you want to check if a name is free or already taken in your form for example, you will want to wait until the user leaves the field ; otherwise if you use the input event, for each input, you will interrogate your server which is a total waste of resources!
The submit
event triggers when a form is submitted. This means that either an input of type="submit"
as been clicked or enter has been pressed in a field. This is usually used to validate the form before sending it to the server or to abort the submission and process it in JavaScript.
Never ever trust the user side of your application. It is possible to get rid of your data control. User side verification should be design with reducing the server side load in mind, not replacing it!
However, the submit
event is not attached to the submit input, but to the form!
The method submit()
of a form allows to initiate form sending, from a JavaScript standpoint. This is useful to manually send our own forms to our server.
When using the submit()
method, no submit event is triggered! Keep that in mind.
The need of dynamically refreshing some part of a web page, and not the whole page, is an important feature in the web now. Indeed, from a server standpoint, sending just some chunck of data is often a more lightweight operation, and from a UX design point of view, the flow stay consistent: only the elements that are supposed to change are actually updated on the page, creating dynamic web page.
Nowadays, you use JSON instead of XML.
In a conventional web application, for retrieving specific elements, a new whole HTML page has to be received. This is not the case whith an asynchrone communication. The most known approach is AJAX. It works as follow
However, this is somewhat similar to all the asynchrone approaches: the DOM is updated asynchronously. In any case, the server should obviously be designed to handle such asynchrone requests.
Asyncrhonous JavaScript And XML (AJAX) is a programming practice designed to build dynamic web pages relying on asynchronous communication. It uses the xmlHttpRequest
to communicate with the server.
However, we will not study this technology, since the fetch API has been recently introduced and is planned to replace it. Nonetheless, almost all the current web site use AJAX for now, so it is important to understand what it is and how to use it.
The Fetch API provides an interface for fetching resources (including across the network). It will seem familiar to anyone who has used XMLHttpRequest, but the new API provides a more powerful and flexible feature set. (source: MDN)
Put in other terms, the Fetch API is a wrapper, a generic definition on how systems request resources and how they respond, and therefore can be extended to much more than network communication.
The basic syntax for fetching resources from a server is simply:
Note that fetch
returns a promise, and without option, your perform a GET request, downloading the content from the url
. Getting a response is a two stages process :
The promise of fetch resolves with a Response
object as soon as the server responds with headers.
The response as to be parsed to gets its content/body.
In the first stage, we usually check the status
code (a property) of the headers received in the response
. The shortcut response.ok
is useful to check if the status code is between 200-299. If not, you know that there was an error during the fetch.
Abnormal error (e.g. 300-499) do not cause an error! Therefore the following code is not equivalent:
Because bad HTTP code will not be caught.
The seconde stage is to get the response body. In the above example, we saw that we do a response.json()
to get that body. This is possible because Reponse
give provides multiple promise-based methods to access the body. Some other examples:
response.text()
: read the response and return a string,
response.blob()
: return the response as a blob object,
response.arrayBuffer()
: return the response as an array buffer.
A body can only be consumed once! You cannot call consecutively response.json()
then response.text()
.
You can also make asynchrone POST
with fetch. To do so, you will need to specify the method, the header and the content (body
) of your request. The body can only be one of the following type:
a string
(e.g. JSON-encoded),
FormData
object, to submit the data as form/multipart
,
Blob
/BufferSource
to send binary data,
URLSearchParams
, to submit the data in x-www-form-urlencoded
encoding, rarely used.
(The JSON format is used most of the time)
Like that, you can for example send an image once uploaded in a form without reloading the entire page.