Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Created Local Persistence Example
  • Loading branch information
aa7401 committed Nov 24, 2019
1 parent 93ab433 commit de83d54
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 2 deletions.
4 changes: 2 additions & 2 deletions .eslintrc.json
Expand Up @@ -8,7 +8,7 @@
"jest": true
},
"parserOptions": {
"ecmaVersion": 8
"ecmaVersion": 2018
},
"rules": {
"arrow-body-style": 2,
Expand All @@ -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",
Expand Down
25 changes: 25 additions & 0 deletions 05 The DOM.md
Expand Up @@ -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:
Expand Down
42 changes: 42 additions & 0 deletions exercises/05_client/contacts/index.html
@@ -0,0 +1,42 @@

<!doctype html>

<html lang="en">
<head>
<meta charset="utf-8">

<title>Contacts</title>
<meta name="description" content="Contacts">
<meta name="author" content="Mark J Tyers">
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<main>
<header>
<h1>Contacts</h1>
</header>
<nav>
<h2>My Contacts</h2>
<ol>
<li>Mr Ted</li>
<li>Sir Moo</li>
</ol>
</nav>
<article>
<form>
<input type="hidden" name="key" />
<p><label for="name">Name</label>
<input name="name" type="text" autofocus /></p>
<p><label for="email">Email</label>
<input name="email" type="email" /></p>
<p>
<button id="submit" type="submit">Add Record</button>
<button id="delete" type="submit">Delete Record</button>
</p>
</form>
<table></table>
</article>
</main>
</body>
</html>
101 changes: 101 additions & 0 deletions 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)
}
58 changes: 58 additions & 0 deletions 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;
}

0 comments on commit de83d54

Please sign in to comment.