Skip to content
This repository has been archived by the owner on Dec 19, 2017. It is now read-only.

Using Middleware to Create Declarative Views

Casey Webb edited this page Dec 18, 2016 · 7 revisions
const componentSetterMiddleware = (ctx) => {
  Object.defineProperty(ctx, 'component', {
    set(component) {
      ko.components.register(ctx.canonicalPath, component)
      ctx.route.component = ctx.canonicalPath
    }
  })
}

const titleSetterMiddleware = (ctx) => {
  Object.defineProperty(ctx, 'title', {
    set(title) {
      document.title = title
    }
  })
}

const homeView = (ctx) => {
  ctx.title = 'Home'
  ctx.component = {
    template: '<h1>Welcome to my App!</h1>'
  }
}

ko.router.use(componentSetterMiddleware)
ko.router.use(titleSetterMiddleware)

ko.applyBindings({
  routes: {
    '/': homeView
  }
})

or, with a little fp magic...

import { assign, curryRight } from 'lodash'

const assignFrom = (...srcs) => curryRight(assign, srcs.length + 1)(...srcs)

const createSetterMiddleware = (prop, middleware) => (ctx) => {
  Object.defineProperty(ctx, prop, {
    set: (v) => middleware(v, ctx)
  })
}

const componentSetterMiddleware = createSetterMiddleware('component', (c, ctx) => {
  ko.components.register(ctx.canonicalPath, component)
  ctx.route.component = ctx.canonicalPath
})

const titleSetterMiddleware = createSetterMiddleware('title', (t) => {
  document.title = t
})

const homeView = assignFrom({
  title: 'Home',
  component: {
    template: '<h1>Welcome to my App!</h1>'
  }
}) 

ko.router.use(componentSetterMiddleware)
ko.router.use(titleSetterMiddleware)

ko.applyBindings({
  routes: {
    '/': homeView
  }
})

You did learn you a Haskell for great good, right?