Skip to content

Instantly share code, notes, and snippets.

@gilbert
Last active October 2, 2015 19:27
Show Gist options
  • Save gilbert/a92c9fd3645d6b2e31ab to your computer and use it in GitHub Desktop.
Save gilbert/a92c9fd3645d6b2e31ab to your computer and use it in GitHub Desktop.
Mithril.js Tutorial Part 2
window.Coupon = {}
Coupon.controller = function (attrs) {
var ctrl = this
ctrl.code = ""
ctrl.submit = function (e) {
e.preventDefault()
ctrl.error = null
validateCoupon(ctrl.code)
.then(function(discount) {
alert('Coupon applied!')
ctrl.code = ""
attrs.onSuccess(discount)
})
.then(null, function(err) {
ctrl.error = err
})
}
}
Coupon.view = function (ctrl) {
return m('form', { onsubmit: ctrl.submit }, [
ctrl.error ? [
m('.error', "Invalid coupon.")
] : null,
m('label', "Enter coupon (if you have one):"),
m('input[type=text]', {
value: ctrl.code,
onchange: function(e) {
ctrl.code = e.currentTarget.value
}
}),
m('button[type=submit]', "Validate coupon")
])
}
function validateCoupon (code) {
var isValid = (code === 'happy')
var discount = 0.20
// Mock AJAX promise
var deferred = m.deferred()
if (isValid) { deferred.resolve(discount) }
else { deferred.reject('invalid_code') }
return deferred.promise
}
window.Entry = {}
var store = []
var idCounter = 1
Entry.all = function () {
return store
}
Entry.create = function (attrs) {
attrs.id = (idCounter += 1)
store.push(attrs)
return attrs
}
Entry.vm = function () {
return {
enteredAt: null,
volunteers: [ Entry.volunteerVM() ]
}
}
Entry.volunteerVM = function () {
return {
name: '[Your name]',
email: '[Your email]'
}
}
window.EntryForm = {}
EntryForm.controller = function () {
var ctrl = this
ctrl.entry = Entry.vm()
ctrl.discount = 0
ctrl.submit = function () {
Entry.create( ctrl.entry )
m.route('/')
}
}
EntryForm.view = function (ctrl) {
return m('.entry-form', [
m('h1', "Entry Form"),
m('h3', "Please enter each volunteer's contact information:"),
m.component(Volunteers, { volunteers: ctrl.entry.volunteers }),
m.component(Total, { /*2*/
count: ctrl.entry.volunteers.length,
discount: ctrl.discount
}),
m.component(Coupon, {
onSuccess: function(newDiscount) {
ctrl.discount = newDiscount
}
}),
m('button', { onclick: ctrl.submit }, 'Submit')
])
}
window.EntryList = {}
EntryList.view = function () {
return m('.entry-list', [
m('h1', "All Entries"),
m('a[href=/entries/new]', { config: m.route }, "Add New Entry"),
Entry.all().map( entryView )
])
}
function entryView (entry) {
var date = new Date(entry.enteredAt)
return m('.entry', [
m('label', "Entered at: ", date.toString()),
m('ul', entry.volunteers.map(volunteerView) )
])
}
function volunteerView (volunteer) {
return m('li.volunteer', [
m('label', volunteer.name),
m('label', "(" + volunteer.email + ")")
])
}
<div id="app"></div>
<script>
// Seed some data
Entry.create({
"enteredAt": 1443018758199,
"volunteers": [
{ name: "Alice", email: "alice@example.com" },
{ name: "Bob", email: "bob@example.com" }
]
})
Entry.create({
"enteredAt": 1443019047227,
"volunteers": [
{ name: "Carl", email: "carl@example.com" },
{ name: "Dan", email: "dan@example.com" },
{ name: "Erl", email: "erl@example.com" },
]
})
// Put the component on the page
m.route(document.getElementById('app'), '/', {
'/': EntryList,
'/entries/new': EntryForm
})
</script>
window.Total = {}
/* Model-level logic */
Total.pricePerCount = 10
Total.calcPrice = function (discount, count) {
var total = count * Total.pricePerCount
return roundCents(total - total * discount)
}
Total.calcDiscount = function (discount, count) {
var total = count * Total.pricePerCount
return roundCents(total * discount)
}
/* View */
Total.view = function (ctrl, attrs) {
return m('.total', [
m('label', "Total: "),
discountView(ctrl, attrs),
m('b', "$" + Total.calcPrice(attrs.discount, attrs.count))
])
}
/* Helpers */
function discountView (ctrl, attrs) {
if (attrs.discount > 0) {
var discountedAmount =
Total.calcDiscount(attrs.discount, attrs.count)
return m('span', "(Coupon discount: -$" + discountedAmount + ")")
}
}
function roundCents (num) {
return Math.round(num * 100) / 100
}
window.Volunteers = {}
Volunteers.controller = function (attrs) {
var ctrl = this
ctrl.add = function () {
attrs.volunteers.push( Entry.volunteerVM() )
}
ctrl.remove = function (idx) {
attrs.volunteers.splice(idx, 1)
}
}
Volunteers.view = function (ctrl, attrs) {
return m('.volunteers', [
attrs.volunteers.map(function(volunteer, idx) {
return m('fieldset', [
m('legend', "Volunteer #" + (idx+1)),
m('label', "Name:"),
m('input[type=text]', {
value: volunteer.name,
onchange: function(e) {
volunteer.name = e.currentTarget.value
}
}),
m('br'),
m('label', "Email:"),
m('input[type=text]', {
value: volunteer.email,
onchange: function(e) {
volunteer.email = e.currentTarget.value
}
}),
removeAnchor(ctrl, attrs, idx)
])
}),
m('button', { onclick: ctrl.add }, 'Add another volunteer'),
])
}
function removeAnchor (ctrl, attrs, idx) {
if (attrs.volunteers.length >= 2) {
return m('button', { onclick: ctrl.remove.papp(idx) }, 'remove')
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment