Javascript - APIs and AJAX

한윤서·2021년 12월 8일
0

Web

목록 보기
5/6

1. Basics of API

What is API

APIs(Application Programming Interfaces) are constructs made available in programming to allow developers to create complex functionality more easily. They abstract complex code away from users allowing more simple syntax.

Types of APIs in client side

APIs in client side of JavaScript are not part of the language itself, but built on top of the language. There are mainly 2 types

  • Browser APIs : Built in web browser and are able to expose data from browser and surrounding computer environment to do useful functions. Common functions
    • Manipulating document (control DOM functions)
    • Fetch data from server (AJAX, Fetch API)
    • Drawing and manipulating graphics (<canvas>)
    • Audio and Video API
  • Third-party API : Not built into browser by default. Have to generally retrieve code and info form somewhere on web. (ex : Twitter API, Google Map API)

Relationship between JS, APIs and other tools

  • Javascript : The high scripting language itself that is built into browser that allows you to implement functionality on web pages
  • Browser API : Constructs built into browser that sits on top of JS to implement functionality more easily
  • Third party API : Constructs built into 3rd party platforms (Ex : Twitter, Google) that allow you to use platform's functionality in own web page
  • JS libraries : One of more JS files containing custom functions that you can attach on web page to enable writing common functionality
    (ex : React, jQuery)
  • JS frameworks : Packages of HTML, CSS, JS and other technologies to use to write an entire web from scratch

Note : Difference between JS library and framework -> Control

  • JS library : Calling a method from library => Developer is in control
  • JS framework : Framework calls the developer's code

How do APIs work

APIs are based on objects

Code interacts with APIs using one or more JS objects which serve as the container for the data the API uses and the functionality provided by API.

The following example shows how various objects related to audio API is related and interacted to play, pause and control volume of mp3 file in web page.

//Web API therefore access by window object
//Audio context : Represents audio graph that can be used to mainpulate audio playing inside browser (has various functions to manipulate audio)
//Audio graph -> general process of how various audio nodes (ex : input, output) interact with each other
const AudioContext = window.AudioContext||window.webkitAudioContext;

//Create AudioContext instance to mainpulate our track
const audioCtx = new AudioContext();

//Create constants that refers to html elements 
const audioElement = document.querySelector('audio');
const playBtn = document.querySelector('button');
const volumeSlider = document.querySelector('.volume');

//Create MediaElementAudioSourceNode which represents the source of audio within <audio> in html page
//access element by audioCtx object (method associated to audio context)
//Inputs audio tag to get access to audio source 
const audioSource = audioCtx.createMediaElementSource(audioElement);

//Event handlers to toggle between play and pause when button is pressed
//Reset display back to beginning when song has finished playing
//Note : arrow functions define this differently -> refers to the scope where function is present
playBtn.addEventListener('click', function() {
    //Check if context is in suspended state initially
    //Activate autoplay
    if(audioCtx.state === 'suspended') {
        audioCtx.resume();
    }
    
    //If track is stopped, play it
    //this refers to the button itself
    if(this.getAttribute('class') == 'paused') {
        audioElement.play();
        this.setAttribute('class', 'playing');
        this.textContent = 'Pause';
    }
    //If track is playing, stop it
    else if(this.getAttribute('class') === 'playing') {
        audioElement.pause();
        this.setAttribute('class', 'paused');
        this.textContent = 'Play';
    }
});

//If track ends
audioElement.addEventListener('ended', function() {
    playBtn.setAttribute('class', 'paused');
    playBtn.textContent = 'Play';
})

//Gain object created to adjust the volume of audio fed through it
const gainNode = audioCtx.createGain();

//Event listener to change the volume by slider
volumeSlider.addEventListener('input', function() {
    gainNode.gain.value = this.value;
})

//Connect the different nodes(input, volume etc) in the audio graph
//audio source -> voume -> destination
//audio node is connected to gain node to adjust volume, which is connected to destination node to be played in computer
audioSource.connect(gainNode).connect(audioCtx.destination);
  • The main key focus is that based on the AudioContext() object created (audioCtx -> rerpesents audio processing graph)
  • the following object acts as the container and it generates audio modules/nodes :
    • audioSource -> audio source node
    • gainNode -> volume node
  • These nodes are then connected to complete the audio graph at the end

APIs have recognaizable entry points

When using an API, the entry point for the API should be clear. In the previous example by using audio API, AudioContext object was the entry point which was needed to do any audio manipulation.

The DOMP API also has a simple entry point -> Its features are generated from the document object. Ex)

const em = document.createElement('em'); // create a new em element
const para = document.querySelector('p'); // reference an existing p element
em.textContent = 'Hello there!'; // give em some text content
para.appendChild(em); // embed em inside para

The Canvas API relies on getting a context object to use to manipulate things. The context object is created by getting a reference to the <canvas> element and then calling the HTMLCanvasElement.getContext() method :

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');

Then the properties and methods can be called by using the context object

APIs use events to handle changes in state

The APIs come in pair with event handlers to take functional actions. Ex)

let requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';
let request = new XMLHttpRequest();
request.open('GET', requestURL);
request.responseType = 'json';
request.send();

request.onload = function() {
  const superHeroes = request.response;
  populateHeader(superHeroes);
  showHeroes(superHeroes);
}
  • The first half of the code creates a new instance of a request object using the XMLHttpRequest() constructor
  • Then it opens a HTTP GET request to retrieve the specified resource
  • Specify that the response should be sent in JSON fromat then send request
  • The onload functions specifies what we do with the response is returned

APIs have additional security mechanisms where appropriate

Web APIs sometimes have additional security mechanisms in place. Ex) some of the more modern WebAPIs will only work on pages served over HTTPS due to them transmitting potentially sensitive data. Also some WebAPIs request permission to be enabled from the user once calls to them are made in your code.

2. Manipulating documents

Structure of web browser

  • Window : Browser tab that a web page is loaded to. Represented by Window object. Functions include
    • Get size of window
    • Manipulate document loaded into that window
    • Store data specific to document on client side
  • Navigator : Represents the state and identity of browser as it exists on the web. Represented by Navigator object
  • DOM : Actual page loaded into the window and represented by Document object. Used to manipulate info on HTML and CSS that comprises the document.

Document Object Model

Document currently loaded in each one of your browser tabs is represented by a document object model. This is a "tree structure" representation created by the browser that enables the HTML structure to be easily accessed by programming languages.

Each element of the document has its own entry and is called a node.

3. Fetching data from server (AJAX)

What is AJAX

  • Asynchronous JavaScript & XML
  • Set of web technologies
  • Send and receive data asyncrhonously
  • Does not interfere with current web page : Does not require page movement
  • JSON has replaced most part of XML due to its convinience

Basic operation of AJAX


AJAX enables asynchronous request to be made by the client. Partial information of the web page can be requested and the server can response to it without the whole page being refreshed.

These technologies allow web pages to directly handle making HTTP requests for specific resources available on a server and formatting the resulting data as needed before it is displayed.

  • Initially a call is made by JS
  • Through the AJAX engine and object from the XmlHttpRequest API is sent.
  • The response is made in XML/JSON form that is transformed to make changes in the client side

Benefits of using AJAX

  • Page updates are a lot quicker and you don't have to wait for the page to refresh, meaning that the site feels faster and more responsive
  • Less data is downloaded on each update, meaning less wasted bandwidth.

XMLHttpRequest(XHR) Object

  • API in the form of object : Has properties and methods associated with it
  • Provided by browsers JS environment
  • Methods transfer data between client/server
  • Can be used with other protocals than HTTP
  • Can work with data other than XML

Basic request using XMLHttpRequest

document.querySelector('#button').addEventListener('click', loadText);

function loadText() {
    //Create XHR object
    let request = new XMLHttpRequest();
    //console.log(request.readyState); -> state = 0

    //OPEN - type of request, url/file address, async
    request.open('GET', 'texf.txt', true);
    //console.log(request.readyState); -> state = 1

    // onload : run when the load event fires (when the response has returned)
    // Response data will be available in "response" property of XHR request object
    request.onload = function() {
        //Print text when text is found (request was successful)
        if(this.status == 200) {
            // console.log(this.responseText);
            document.getElementById('text').innerHTML = this.responseText;
        } 
        else if(this.status == 404){
            //console.log('Not found');
            document.getElementById('text').innerHTML = '404 Not Found';
        }
    }
	//Sends request to server
    request.send();
}
  • When button is clicked, function loadText() is activated
  • Inside the function, a request object is instantiated from XMLHttpRequest() class
  • The open() method specifies what HTTP request method to use to request the resource from the network, and what its URL is
  • The onload is an event listener that executes when the response has returned -> Executes when the readyState value reaches 4
  • There are other event listeners
    • onreadystatechange : Executes function regardless of state (starts from 1 and executes request and state gradually is processed)
    • onprogress : Executes on readystate value of 3
  • Based on the loaded request, data received from the server is then transfered to the DOM elements and shown to users
  • The file can be in different forms from text files to JSON. If JSON, you would need to use JSON.parse() to be able to convert the text format of JSON to objects that would be recognized by the web page.

Note :

  • readyState values
    • 0 : request not initialized -> before open()
    • 1 : Server connection established -> right after open()
    • 2 : request received -> after send() established
    • 3 : processing request -> in process
    • 4 : request finished and response is ready
  • HTTP status value
    • 200 : found
    • 403 : forbidden
    • 404 : Not found

Request using Fetch API

fetch() returns a promise, which resolves to the response sent back from the server — we use .then() to run some follow-up code after the promise resolves, which is the function we've defined inside it.

The following example shows how to print an array of student info stored in a JSON file in the web.

function getUser() {
    fetch('user.json')
    .then((response)=>(response.json()))
    .then((data)=> {
        let output = `<h2>Users</h2>`;
        data.forEach(function(user){
            output += `
                <ul class="list-group mb-3">
                    <li class="list-group-item">ID : ${user.id}</li>
                    <li class="list-group-item">Name : ${user.name}</li>
                    <li class="list-group-item">EMail : ${user.email}</li>
                </ul>
            `
        });
        document.getElementById('output').innerHTML = output;
    })
}
  • The .json() method takes the raw data contained in the response body and turns it into json.
    Note : The following can be in various forms such as .text() or .blob()
  • The returned promise is then sent to the .then() to deal with the json object.

Request using axios

Similar to fetch in the term that it is based on promise to deal with Http request and response. Different from fetch that :

  • It is not built in therefore must install the module
  • Better compatibility with multiple browsers compared to fetch

It is also possible to use async/await together with the axios methods to have better readability

Ex of GET and POST request from client side

//GET request
(async () => {
  try {
    const result = await axios.get('http://www.google.com');
    console.log(result);
    console.log(result.data);
  } catch(error) {
      console.log(error);
  }
})();

//POST request
(async () => {
  try {
    const result = await axios.post('http://www.google.com', {
      name : 'Yoonseo Han',
      age : '22'
    });
    console.log(result);
    console.log(result.data);
  } catch(error) {
      console.log(error);
  }
})();

The main difference between GET and POST request is that POST sends data as a property to the server.

Form Data

Function to dynamically control data from the HTML form tags. Normally comes together with AJAX.

const formData = new FormData();
formData.append('name', 'Yoonseo Han');
formData.has('name');	//Returns true
formData.get('name');	//Returns Yoonseo Han
formData.delete('name');

Can store data in the form of key:value by using the append() method from the generated object.

Then the generated form data can be sent as the second parameter for the POST request to send it to server

const result = await axios.post('http://www.google.com', formData);

4. Third-party APIs

Found in 3rd party APIs

Are APIs that are provided by an external third party. Unlike Browser APIs that are built into the browser - you can access them from JS immediately, they are located on 3rd party servers and to access them from JS, you first need to connect to the API functionality and make it available on your page.
Ex) linking to a JavaScript library available on the server via a <script> element

<script src="https://api.mqcdn.com/sdk/mapquest-js/v1.3.2/mapquest.js"></script>
<link type="text/css" rel="stylesheet" href="https://api.mqcdn.com/sdk/mapquest-js/v1.3.2/mapquest.css"/>

Usually require API keys

Third party APIs tend to use developer keys to allow developers access to the API functionality, which is more to protect the API vendor than the user.

Ex)

L.mapquest.key = 'YOUR-API-KEY-HERE';

Requiring a key enables the API provider to hold users of the API accountable for their actions. When the developer has registered for a key, they are then known to the API provider, and action can be taken if they start to do anything malicious with the API (such as tracking people's location or trying to spam the API with loads of requests to stop it working, for example).

5. Client-side storage

Client-side storage consists of JS APIs that allow you to store data on client and then retrieve when needed. These were used on the purpose on

  • Personalizing site preference
  • Persisting previous site activity (ex : storing items in shopping cart)
  • Saving web application generated documents locally for use offline

The requirement of client-side storage would mainly be due to the characteristics of HTTP of being stateless.

Old method : Cookies

HTTP cookie is a small piece of data that a server sends to user's web browser.The browser may store the cookie and send it back to the same server with later requests. These days cookies arent used that much however is stil used for storing data related to user personalization and state, e.g. session IDs and access tokens

Process of using cookies

  • Where is the cookie produced : When the browser first accesses web page, the web server sends it to the browser
  • Cookie's basic structure : Cookies name and value
  • Where is the cookie stored : The brower stores it in the local computer in the form of file
  • When is the cookie used :

General structure
name=value; Expires=[Date]; Domain=[Domain]; Path=[Path]; [Secure]; HttpOnly

Set-Cookie and Cookie headers

Set-Cookie : Sends cookies from the serer to user agent with the following structure
Set-Cookie: <cookie-name>=<cookie-value>

Ex)

HTTP/2.0 200 OK
Content-Type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

Then, with every subsequent request to the server, the browser sends all previously stored cookies back to the server using the Cookie header.

GET /sample_page.html HTTP/2.0
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry

Lifetime of a cookie can be defined in 2 ways

  • Session cookies : Deleted when current session ends. Browser defines when the current session ends. (some browsers use session restoring when restarting -> cookies last)
  • Permanent cookies : Deleted ata a date specified by Expires attribute
    Ex) Set-Cookie: id=yooncer00; Expires=Thu, 31 Oct 2021 07:28:00 GMT;

Restrict access to cookies

To ensure cookies are sent securely without access of uninted parties : Use Secure and HttpOnly attribute

Secure : A cookie with the following attribute is only sent to server with an encrypted request over the HTTPS protocolo (not sent with HTTP). Insecure sites (with http:) can't set cookies with Secure attribute

HttpOnly : A cookie with the following attribute is inaccessible by JS and cant be modified using Document.cookie. It is only sent to server

Where cookies are sent

The Domain and Path attributes define the scope of a cookie : What URLs the cookies should be sent to

  • Domain attribute
    Specifies which hosts can receive a cookie. If unspecified, the attribute defaults to the same host that initially set the cookie, excluding subdomains. IF Domain is specified -> subdomains are always included
    Ex) Domain=mozilla.org, then cookies are available on subdomains like developer.mozilla.org

  • Path attrivute
    Indicates a URL path that must exist in the requested URL domain's subfile to send the Cookie header
    Ex) Path=/docs, the following /docs, /docs/Web/ paths match

Using Javascript to access cookies

It is possible to create a new cookie via JS using the Document.cookie property.

//Set cookie property name and value
//Set the expire date of cookie
function setCookie(name, value, expireDate) {
    //escape() : encode a string to change to from that URL can recognize
    let cookieStr = name + '=' + escape(value) +
    ((expireDate==null)?"":("; expires" + expireDate.toGMTString()));
    document.cookie = cookieStr;
}

New method : Web Storage and IndexedDB APIs

  • Web storage API : Provides a very simple syntax for storing and retrieving smaller data items consisting of a name and corresponding value -> Useful for storing simple data
  • IndexedDB API : Provides browser with complete database system for storing complex data -> Used to store complete sets of customer records to complex data such as audio files

Web Storage API - Storing simple data

Characteristics of web storage

  • Stores data in the form of string only
  • Is consisted of (key, value)
  • Item with equal key can't exist
  • Both key and value is case-sensitive

There are 2 tpes of web storage :

  • Session storage
  • Local storage

Session storage

Session storage is created and destroyed together with the session. A session is the linked situation between the browser window and website.

Session storage persists data for as long as the browser is open, and the data is lost when the browser is closed. Therefore even though multiple windows open the same website with the same domain, as the windows are different there is a unique session storage for each window.

Local storage

Local storage is created for each web server (regardless of window). The local storage is not cleared eventhough the window accessing the storage is closed. Also multiple windows share the same local storage therefore share data with each other.

Use Web Storage API using js

When a web page is loaded on browser window, the session storage and the local storage is automatically defined in the local computer, with 2 objects to access them :
sessionStorage, localStorage

Storing item or modifying value of item

localStorage.setItem("score", "A+");
localStorage["score"] = "A+";

Getting the value of item stored in storage

let myScore = localStorage.getItem("score");
let myScore = localStorage["score"];

Note : If there is no key item with the following name, null is returned

Remove Item in storage with following name

localStorage.removeItem("score");

Clear al items stored in storage

localStorage.clear();

Get key value of each item

To be able to access each item, we need the key value. Therefoe

let key = sessionStorage.key(ind);

following method returns the key value in the following index

Note : The order of items stored is not equal to the order the items were added to the storage

Web storage event

When there is a change in the web storage, the browser initiates an event and notices it to different windows that is connected to the following webpage.
-> A storage event is initiated and sended to every other window to notice change of stored data

Properties of StorageEvent
key : The string of the changed item's key. If event initiated due to clear(), return null
newValue : The value of the item(key) that has changed
oldValue : The previous value of the item(key) before changed. If a new item was included, return null
storageArea : Web storage object in which event happend
url : Web page's url that caused event

//Listen for storage event -> when there is change in local or session storage
window.addEventListener("storage", storageEventListener);
//Event sent to another window (not the one opened right now)
function storageEventListener(event) {  //event : Object of StorageEvent
    let eventDetail = `key : ${event.key},
    Old value : ${event.oldValue},
    New value : ${event.newValue},
    Storage area : ${event.storageArea},
    url : ${event.url}
    `;
    console.log(eventDetail);
    document.getElementById("textarea").innerHTML = eventDetail;
}

Indexed DP API

IndexedDB is a transactional database system which is a JavaScript-based object-oriented database. IndexedDB lets you store and retrieve objects that are indexed with a key.

The main structure of each IndexedDP :

  • Database
  • A single database consists of multiple database object stores
  • Each object store stores the key and its values associated with the key

Basic terminology of IDB

  • Database : Highest level of IndexedDB
  • Object store : Individual bucket to store data. Typically there is one object store for each type
  • Index : Kind of object store for organizing data in another object store(called the reference object store) by an individual property of data

Implementation of IndexedDB - Initial set up

Main function

Initially, the user would have to set and open up a database when the window is loaded (by using event hanlder).

window.onload = function() {
    //Open database; it is created if it doesnt exist
    //Creates a variable to open version 1 of a database with the name "notes_db"
    //Database operations takes time : Therefore operations are asynchronous
    //Create a request object then use event handlers to run code when request completes
    let request = window.indexedDB.open('notes_db',1);
}

After setting up the database, it is refered by using an additional variable request. The variable adds event listeners to respond the 3 events that may happen after request is made to catch the DB :

  • .onerror : When database didn't open successfully
  • .onsuccess : when database opened successfully -> request returns Database
  • .onupgradeneeded :
    • Set up database table if has not been done previously (database is opened but is empty with no table)
    • Or if databse is opened with a bigger version number than the existing stored database
    • This is where the structure of the database is defined
    • Activates first to structure the db, then onsuccess handler triggered to open database request

The following events will be updated every time the window is refreshed and loaded again.
Within the .onload event handler, the following event handlers are added :

//onerror handler : When database didn't open successfully
request.onerror = function() {
    alert('Database failed to open');
};

//onsuccess handler : when database opened successfully
//Request returns successfully
request.onsuccess = function() {
    console.log('Database opened successfully');
    //store the opened database object in the db variable
    //db variable manipulates database
    db = request.result;
    //Run the function to display the data inside the DB
    displayData();
};

//Update when change in database occurs : Define database structure
request.onupgradeneeded = function(event) {
    //Grab a reference to the opened database
    let db = event.target.result;

    //Create a new object store inside our opened database
    let obejctStore = db.createObjectStore('note_os', {keyPath : 'id', autoIncrement : true});

    //Define what data items the objectStore will contain
    obejctStore.createIndex('title', 'title', {unique:false});
    obejctStore.createIndex('text', 'text', {unique:false});

    console.log('Database setup complete');
};

Define object store

To define the structue of the DB using object store, the following method was used inside the .onupgradeneeded event listener

 let obejctStore = db.createObjectStore('note_os', {keyPath : 'id', autoIncrement : true});
  • To store our notes in db : Object store is equivalent to single table in conventional database system
  • Specified autoincrement key filed called "id" -> Each new record will automatically be given an incremented value , Used to uniquely identify records
  • If you want to change an existing object store, you must delete the old object store and create it again with new options
  • There can be multiple object stores in single database
  • For each object store, a key is assigned to identify each item in the store
  • The following example assigns an automatically incrementing value to a property called "id" that acts as the key

Note : For each record, object store can derive key from on of 3 sources : key generator, key path or explicitly specified value

  • key generator : Mechanism for producing new keys in ordered sequence
    autoIncrement creates a unique number that is automatically incremented
  • key path : Defines where browser should extract the key from in the object store or index -> collection of multiple keys (can be single)
    keyPath : 'id' assigns the id property as the primary key

However combination of key generator + key path is also available(like the previous example shown).

Define indexes

Then within the object store, indexes(fields) are added. Indexes are a kind of object store used to retrive data from the reference object store by a "specified" property.

Index lives inside the reference object store and contains the same data, but uses a specified property as its key path instead of the reference store's primary key.

obejctStore.createIndex('title', 'title', {unique:false});
obejctStore.createIndex('text', 'text', {unique:false});

The syntax is

var myIDBIndex = objectStore.createIndex(indexName, keyPath, objectParameters);
  • first argument : Name of the new index
  • second argument : Property on the data you want to index
  • Third argument : unique and multiEntry
    unique -> Whether index allows duplicate values for single key
    multiEntry -> Determine how method behabes when indexed property is an array

Implementation of IDB - Working with data

All operations in IDB are asynchronous, using promises where the IDP API uses requests. All data operations in IndexedDB are carried out inside a transaction with the following form :
1) Get database object
2) Open transaction on database
3) Open object store on transaction
4) Perform operation on object store

Transaction

//First argument : List of object stores that the transaction will span (pass empty array if you want transaction to sapn all object stores)
//Second argument : Defines type of transaction (if empty : get read-only transaction)
let transaction = db.transaction(['note_os'], 'readwrite');
//call and access an object store that is currently in the database
//access through the returned transaction object
let objectStore = transaction.objectStore('note_os');
  • Open a read/write db transaction using the transaction method
  • transaction() takes 2 arguments and returns a transaction object -> transaction object allows us to access the object store and modify it
  • First argument : List of object stores that the transaction will span (pass empty array if you want transaction to sapn all object stores)
  • Second argument : Defines type of transaction to readonly (when does not change data but only get the data value) or readwrite
  • Then based on the transaction, we access one of the object stores inside the database

Add data to DB


function addData(event) {
    //prevent default
    event.preventDefault();

    //Grab the values entered into the form fields and store them in a temporary object to be inserted into DB
    //Dont need to specify id value - auto generated
    let newItem = {title : titleInput.value, text : textInput.value};
    //Open transaction
    let transaction = db.transaction(['note_os'], 'readwrite');
    let objectStore = transaction.objectStore('note_os');
  
    //Make request to add new item object to the object store
    //Event handlers required for request when task is completed
    let request = objectStore.add(newItem);

    //When request is finished : eventhandlers 
    request.onsuccess = function() {
        //When new object added to object store, clear the form : ready for another entry
        titleInput.value='';
        textInput.value='';
    };

    //When transaction has successfully finished, 
    transaction.oncomplete = function() {
        console.log(`Transaction completed : Database modification finished.`);
        //Update the display of data to show the newly added item
        displayData();
    };

    transaction.onerror = function() {
        console.log('Transaction not opened due to error');
    };
}

To add new data inside the IDB, .add() method is used in the following syntax :

someObjectStore.add(data, optionalKey);
  • Second argument defines the primary key for individual object on creation, but only is used if key path is not specified
  • Data parameter can be data of any type but has to match the keypath of the object store

Delete data from DB

To delete data, call the delete method on the object store

someObjectStore.delete(primaryKey);

In the following example :

function deleteItem(event) {
    //Retrieve name of the task we want to delete
    //Convert it to a number before using it with DB : Because attribute is stored in string from (retrieved from DB)
    //The event target points to the button itself -> paretnode is the list tag
    let noteId = Number(event.target.parentNode.getAttribute('data-node-id'));

    //Open transaction object and delete the task, finding it using the id we retrieved above
    let transaction = db.transaction(['note_os'], 'readwrite');
    let objectStore = transaction.objectStore('note_os');
    //Delete the record with followin id from the DB
    let request = objectStore.delete(noteId);

    //Report the data item has been deleted from the DB
    transaction.oncomplete = function() {
        //Delete the parent of the button -> list item, so no longer displayed
        event.target.parentNode.parentNode.removeChild(event.target.parentNode);
        console.log(`Note ${noteId} deleted`);

        //If list item is empty, display a notice message
        if(!noteList.firstChild) {
            let listItem = document.createElement('li');
            listItem.innerText = 'No notes stored';
            noteList.appendChild(listItem);
        }
    }
}

Retrieve data from DB

To read data, call the get method on the object store.

someObjectStore.get(primaryKey);

Retrieving all the data from DB

A method to retrieve all of the data is to use a cursor. A cursor selects each object in an object store or index one by one.

A cursor is created by

someObjectStore.openCursor(optionalKeyRange, optionalDirection);

Then it returns a promise that resolves with a cursor object representing the first object in the object store or undefined if there is no object.

//openCursor() method to open a request for a cursor 
//Then chain event handlers to deal when cursor is successfully returned
objectStore.openCursor().onsuccess = function(event) {
    //Get reference to the cursor (result of the openCursor() when successfully returned)
    let cursor = event.target.result;

    //If the cursor contains a record from the data store
    if(cursor) {
        //Create a list and display it by adding to HTML -> append inside the list
        const listItem = document.createElement('li');
        const h3 = document.createElement('h3');
        const para = document.createElement('p');

        listItem.appendChild(h3);
        listItem.appendChild(para);
        noteList.appendChild(listItem);

        //Put the data from the cursor inside the h3 and para variable
        h3.textContent = cursor.value.title;
        para.textContent = cursor.value.text;

        //Store the id of the data item inside an attribute of the list item
        listItem.setAttribute('data-node-id', cursor.value.id);

        //Create delete button and place it in each list
        const deleteBtn = document.createElement('button');
        listItem.appendChild(deleteBtn);
        deleteBtn.textContent = 'Delete';
        //Event handler so that when button is clicked, list is deleted
        deleteBtn.onclick = deleteItem;

        //Iterate to next item(record) in the cursor
        cursor.continue();
    } else {
        //When list is empty, display message
        if(!noteList.firstChild) {
            const listItem = document.createElement('li');
            listItem.textContent = 'No notes stored';
            noteList.appendChild(listItem);
        }

        //No more cursor items to iterate 
        console.log('Notes all displayed');
    }
}

Use database versioning

When we call idb.open : specifies the database version number in 2nd parameter. If version number is greater than version of existing databse, onupgradeneeded is executed -> Allows to add object stores and indexes to database

UpgradeDB object has special oldVersion property that indicates the version number of database existing in browser

var dbPromise = idb.open('test-db7', 2, function(upgradeDb) {
  switch (upgradeDb.oldVersion) {
    case 0:
      upgradeDb.createObjectStore('store', {keyPath: 'name'});
    case 1:
      var peopleStore = upgradeDb.transaction.objectStore('store');
      peopleStore.createIndex('price', 'price');
  }
});
  • In the following example, we have set the newest version of the database at 2
  • The database does not yet exist in browser and therefore upgradeDb.oldVersion has the value of 0
  • By starting from the version 0, a "store" object store is added to the database
  • Browser continues executing through case 1 creating a "price" index on "store" object store
  • Once it has finished executing, the databsae in browser it at version 2 and contains a "store" object store with a "price" index
profile
future eo

0개의 댓글