From de83d545f2124ad262ce33449930d136b8e223f7 Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Sun, 24 Nov 2019 21:08:00 +0000 Subject: [PATCH] Created Local Persistence Example --- .eslintrc.json | 4 +- 05 The DOM.md | 25 ++++++ exercises/05_client/contacts/index.html | 42 ++++++++++ exercises/05_client/contacts/script.js | 101 ++++++++++++++++++++++++ exercises/05_client/contacts/style.css | 58 ++++++++++++++ 5 files changed, 228 insertions(+), 2 deletions(-) create mode 100644 exercises/05_client/contacts/index.html create mode 100644 exercises/05_client/contacts/script.js create mode 100644 exercises/05_client/contacts/style.css diff --git a/.eslintrc.json b/.eslintrc.json index 05aae6b..e1265f1 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -8,7 +8,7 @@ "jest": true }, "parserOptions": { - "ecmaVersion": 8 + "ecmaVersion": 2018 }, "rules": { "arrow-body-style": 2, @@ -30,7 +30,7 @@ "max-lines-per-function": ["error", 25], "max-nested-callbacks": ["error", 4], "max-params": ["error", 5], - "max-statements": ["error", 10], + "max-statements": ["error", 15], "no-cond-assign": 2, "no-dupe-args": "error", "no-dupe-keys": "error", diff --git a/05 The DOM.md b/05 The DOM.md index 661a714..afaa104 100644 --- a/05 The DOM.md +++ b/05 The DOM.md @@ -59,12 +59,37 @@ e.target.parentElement.firstChild.innerHTML ## 2 Form Validation +Now you have mastered DOM manipulation its time to move onto one of the most common uses of client-side JavaScript, form validation. The base code can be found in the `exercises/05_client/contacts/` directory. In the previous example we opened the `index.html` file using the `files://` protocol by dragging the html file into the chrome browser. Since we will be implementing some features that don't support this we need to access the page over `http://`. One way would be to create a koa script that serves static content however a quick and simple solution is to use the [`serve`](https://www.npmjs.com/package/serve) package. This needs to be installed and run from the `contacts/` directory. + +```javascript +$ npm install serve +$ ./node_modules/.bin/serve + ┌──────────────────────────────────────────────────┐ + │ │ + │ Serving! │ + │ │ + │ - Local: http://localhost:5000 │ + │ - On Your Network: http://10.17.114.20:5000 │ + │ │ + │ Copied local address to clipboard! │ + │ │ + └──────────────────────────────────────────────────┘ +``` + +Now you can paste the url into the chrome browser to access the page over http! Since the code is loaded by the browser you don't need to restart this server after making changes to the code. Remember to stop the server using `ctrl+c` when you have stopped working on the site. + Handling form validation Revealing sections of the form Preventing form submission +### 2.1 Data Persistence + +If you close your browser down and re-open it you will see that the contacts you added have been persisted! The data is stored within the browser using a document database techology called [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Basic_Concepts_Behind_IndexedDB). + +Viewing the data. + ## 3 Making API Calls In this section you will learn how to retrieve data from an API, specifically we will be covering: diff --git a/exercises/05_client/contacts/index.html b/exercises/05_client/contacts/index.html new file mode 100644 index 0000000..960478a --- /dev/null +++ b/exercises/05_client/contacts/index.html @@ -0,0 +1,42 @@ + + + + + + + + Contacts + + + + + + +
+
+

Contacts

+
+ +
+
+ +

+

+

+

+

+ + +

+
+
+
+
+ + diff --git a/exercises/05_client/contacts/script.js b/exercises/05_client/contacts/script.js new file mode 100644 index 0000000..7857011 --- /dev/null +++ b/exercises/05_client/contacts/script.js @@ -0,0 +1,101 @@ + +'use strict' + +const minNameLength = 3 +const minEmailLength = 10 + +document.addEventListener('DOMContentLoaded', async() => getAll()) + +function selectContact(e) { + // We access the id attribute of the link we clicked + const key = e.target.getAttribute('id') + // And use this to retrieve the relevant record + const data = JSON.parse(localStorage.getItem(key)) + // Now we insert the data into the form + document.querySelector('input[name="name"]').value = data.name + document.querySelector('input[name="email"]').value = data.email + document.querySelector('input[name="key"]').value = key + // now we change the text on the button and rewire the event handler + document.querySelector('button#submit').innerHTML = 'Update Record' + document.querySelector('button#submit').onclick = updateContact + // finally we reveal the delete button + document.querySelector('button#delete').classList.remove('hidden') + return false +} + +function updateContact() { + // we grab all the data from the form's input boxes into an object + const data = Array.from(document.querySelectorAll('input')).reduce( (acc, val) => { + if(val.name !== 'key') acc[val.name] = val.value + return acc + }, {}) + // next we get the record key stored in the hidden field + const key = document.querySelector('input[name="key"]').value + // and finally store the updated data using the same key + localStorage.setItem(key, JSON.stringify(data)) + // lastly we reload the contact list + getAll() + return false +} + +function deleteContact() { + // we get the record key stored in the hidden field + const key = document.querySelector('input[name="key"]').value + // and delete that object from localstorage + localStorage.removeItem(key) + // lastly we reload the contacts list + getAll() + return false +} + +function clearForm() { + // we delete the data from all the input boxes + document.querySelector('input[name="name"]').value = '' + document.querySelector('input[name="email"]').value = '' + // return the cursor focus to the name field + document.querySelector('input[name="name"]').focus() + // change the button text + document.querySelector('button').innerHTML = 'Add Record' + // wire the button to the add function + document.querySelector('button').onclick = addContact + document.querySelector('button#delete').onclick = deleteContact + // hide the delete button + document.querySelector('button#delete').classList.add('hidden') +} + +function addContact() { + if (document.querySelector('input[name="name"]').value.length < minNameLength) return false + if (document.querySelector('input[name="email"]').value.length < minEmailLength) return false + const data = Array.from(document.querySelectorAll('input')).reduce( (acc, val) => { + if(val.name !== 'key') acc[val.name] = val.value + return acc + }, {}) + const key = getHash() + localStorage.setItem(key, JSON.stringify(data)) + getAll() + return false +} + +function getAll() { + const items = {...localStorage} // spread operator to return all keys + const list = document.querySelector('ol') + list.innerHTML = '' + for(const key in items) { + const listItem = document.createElement('li') + const link = document.createElement('a') + link.onclick = selectContact + link.setAttribute('href', '#') + link.setAttribute('id', key) + link.innerHTML = JSON.parse(items[key]).name + listItem.appendChild(link) + list.appendChild(listItem) + } + clearForm() +} + +function getHash() { + const hashLen = 36 + const keyLen = 8 + const offset = 2 + return Math.random().toString(hashLen).substr(offset, keyLen) +} diff --git a/exercises/05_client/contacts/style.css b/exercises/05_client/contacts/style.css new file mode 100644 index 0000000..cd13711 --- /dev/null +++ b/exercises/05_client/contacts/style.css @@ -0,0 +1,58 @@ + +body { + font-family: verdana; +} + +table { + margin: 20px; + border-spacing: 0; +} + +td { + border: 1px solid grey; + margin: 0; + padding: 5px; +} + +header { + height: 120px; + background-color: #999; +} + +h1, h2 { + padding: 20px; +} + +h2 { + font-size: 1.2em +} + +/* button#delete { + visibility: hidden; +} */ + +.hidden { + visibility: hidden; +} + +form { + background-color: #666; + padding: 20px; + padding-left: 220px; +} + +main { + width: 800px; + background-color: yellow; + margin: auto; +} + +nav { + width: 200px; + background-color: grey; + float: left; +} + +article { + background-color: #ccc; +}