Skip to content

Instantly share code, notes, and snippets.

@sttt
Created February 17, 2018 10:26
Show Gist options
  • Save sttt/71e2114565c927384bdcedc7a7d38d57 to your computer and use it in GitHub Desktop.
Save sttt/71e2114565c927384bdcedc7a7d38d57 to your computer and use it in GitHub Desktop.
3. Weekly JavaScript Challenge
<nav>
<div class="container">
<div class="nav-wrapper">
<a href="#" class="brand-logo">Invoice form</a>
<p class="date-saved">Last saved: <span data-savetime>07.02 21:25</span></p>
</div>
</div>
</nav>
<main class="container">
<div class="row">
<form class="col s12" data-form>
<div class="row">
<div class="col s12"><h5>Your details</h5></div>
<div class="input-field col s12 m6">
<input id="first_name" type="text" class="validate">
<label for="first_name">First Name</label>
</div>
<div class="input-field col s12 m6">
<input id="last_name" type="text" class="validate">
<label for="last_name">Last Name</label>
</div>
</div>
<div class="row">
<div class="input-field col s12 m5">
<input id="address" type="text" class="validate">
<label for="address">Address</label>
</div>
<div class="input-field col s7 m4">
<input id="city" type="text" class="validate">
<label for="city">City</label>
</div>
<div class="input-field col s5 m3">
<input id="postcode" type="text" class="validate" maxlength="6" pattern="[0-9]{2}-[0-9]{3}">
<label for="postcode">Postcode</label>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<input id="email" type="email" class="validate">
<label for="email" data-error="Invalid email address">Email</label>
</div>
</div>
<div class="row">
<div class="col s12"><h5>Company details</h5></div>
<div class="input-field col s12 m7">
<input id="company_name" type="text" class="validate">
<label for="company_name">Name</label>
</div>
<div class="input-field col s12 m5">
<input id="company_nip" type="text" minlength="10" maxlength="10" pattern="[0-9]+" class="validate" length="10">
<label for="company_nip" data-error="Invalid number">NIP</label>
</div>
</div>
<div class="row">
<div class="input-field col s12 m5">
<input id="company_address" type="text" class="validate">
<label for="company_address">Address</label>
</div>
<div class="input-field col s7 m4">
<input id="company_city" type="text" class="validate">
<label for="company_city">City</label>
</div>
<div class="input-field col s5 m3">
<input id="company_postcode" type="text" class="validate" maxlength="6" pattern="[0-9]{2}-[0-9]{3}">
<label for="company_postcode">Postcode</label>
</div>
</div>
<div class="row">
<div class="col s12"><h5>Invoice details</h5></div>
<div class="input-field col s12">
<input id="price" type="number" min="0" step="0.01" class="validate">
<label for="price">Price</label>
</div>
<div class="col s12">
<p>Status</p>
<div class="row">
<div class="col s6 m3">
<input name="status" type="radio" id="generated" />
<label for="generated">Generated</label>
</div>
<div class="col s6 m3">
<input name="status" type="radio" id="sent" />
<label for="sent">Sent</label>
</div>
<div class="col s6 m3">
<input name="status" type="radio" id="paid" />
<label for="paid">Paid</label>
</div>
<div class="col s6 m3">
<input name="status" type="radio" id="overdue" />
<label for="overdue">Overdue</label>
</div>
</div>
</div>
</div>
</form>
</div>
</main>
const InvoiceForm = (() => {
let _lastSave = null
const _elSavetime = document.querySelector('[data-savetime]')
const _elForm = document.querySelector('[data-form]')
const _elTextFields =
document.querySelectorAll('[data-form] input, [data-form] textarea')
const _elCheckFields =
document.querySelectorAll('[data-form] input[type=radio], [data-form] input[type=checkbox]')
const _updateSavetime = () => {
let time = _lastSave ? _lastSave : 'never'
_elSavetime.textContent = time
}
const _initSavetime = () => {
localforage.getItem('savetime')
.then(value => {
_lastSave = value
_updateSavetime()
})
}
const _initForm = () => {
localforage.getItem('form')
.then(value => {
_initFormFields(value)
})
}
const _setSavetime = () => {
const date = new Date()
const day = date.getDate()
const month = date.getMonth() + 1
const year = date.getFullYear()
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
_lastSave = `${day}/${month}/${year} ${hour}:${minute}:${second}`
localforage.setItem('savetime', _lastSave)
.then(_updateSavetime)
}
const _setSerializedForm = () => {
const allValues = Array.from(_elTextFields)
const textfieldValues = allValues
.filter(el => (
el.value && !(el.type === 'radio' || el.type === 'checkbox')
))
.map(el => ({ id: el.id, value: el.value }))
const checkfieldValues = allValues
.filter(el => el.checked)
.map(el => el.id)
localforage.setItem('form', {
textfields: textfieldValues,
checkfields: checkfieldValues
}).then(() => {
Materialize.toast('Form saved!', 3000, 'green lighten-1')
})
}
const _onFormChange = () => {
_setSavetime()
_setSerializedForm()
}
const _initFormFields = form => {
form.textfields.forEach(el => {
const field = document.getElementById(el.id)
field.value = el.value
})
form.checkfields.forEach(el => {
const field = document.getElementById(el)
field.checked = true
})
Materialize.updateTextFields()
}
const init = () => {
_initSavetime()
_initForm()
const debounceFormChange = _.debounce(_onFormChange, 500)
Array.from(_elTextFields).forEach(field => {
field.addEventListener('input', debounceFormChange)
})
Array.from(_elCheckFields).forEach(field => {
field.addEventListener('change', debounceFormChange)
})
}
return {
init: init
}
})()
InvoiceForm.init()
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.12.0/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/js/materialize.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/localforage/1.4.2/localforage.min.js"></script>
body {
padding-bottom: 3rem;
}
nav {
margin-bottom: 3rem;
}
.date-saved {
float: right;
font-size: .9rem;
margin: 0;
font-style: italic;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/css/materialize.min.css" rel="stylesheet" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment