Compassus
A routing library for Om Next.
Install / Use
/learn @compassus/CompassusREADME
Compassus 
A routing library for Om Next.
Read the announcement blog post.
Contents
Installation
Leiningen dependency information:
[compassus "1.0.0-alpha3"]
Maven dependency information:
<dependency>
<groupId>compassus</groupId>
<artifactId>compassus</artifactId>
<version>1.0.0-alpha3</version>
</dependency>
Template:
There is a Boot / Leiningen template that provides the minimum boilerplate to help you get started with a Compassus project.
Guide
To get started, require Compassus somewhere in your project.
(ns my-app.core
(:require [om.next :as om :refer-macros [defui]]
[compassus.core :as compassus]))
Declaring routes
Your application's routes are represented by a map of keywords (the route handlers of your application) to the respective Om Next component classes. The following example shows the routes for a simple application that has 2 routes, :index and :about:
(defui Index
...)
(defui About
...)
(def routes
{:index Index
:about About})
To specify the initial route of the application, use the :index-route configuration
key in the Compassus application configuration map:
(def app
(compassus/application
;; :index is the initial route of the application
{:routes {:index Index
:about About}}
:index-route :index))
Routes can also be idents. Below is an example route definition that uses an ident as the route key.
(defui Item
...)
(defui ItemList
...)
{:items ItemList
[:item/by-id 0] Item}
Assembling a Compassus application
Creating a Compassus application is done by calling the application function.
This function accepts a configuration map that should contain your routes and
an Om Next reconciler. Note that the parser must be constructed with compassus.core/parser.
Here's an example:
(def app
(compassus/application
{:routes {:index Index
:about About}
:index-route :index
:reconciler (om/reconciler
{:state {}
:parser (compassus/parser {:read read})})}))
Implementing the parser
The parser is a required parameter to an Om Next reconciler. As such, a Compassus application also needs to have one, with the added advantage that most of the plumbing has been done for you. The parser in a Compassus application will dispatch on the current route. Therefore, all that is required of a parser implementation is that it knows how to handle the routes that your application will transition to. An example is shown below with routes we have previously declared.
For convenience, the parser's env argument contains a :route key with the current
route of the Compassus application.
;; we declared routes for `:index` and `:about`.
;; our parser should dispatch on those keys:
(defmulti read om/dispatch)
(defmethod read :index
[env k params]
{:value ...
:remote ...})
(defmethod read :about
[env k params]
{:value ...
:remote ...})
In some cases you may not want the parser to dispatch on your application's current
route, but instead on the query that its component declares. This is optionally
possible by passing an optional :route-dispatch key in the configuration map
passed to compassus.core/parser. If set to false, the parser will not dispatch
on the current route, but instead on the query of the component pertaining to that
route. Here's an example:
(defui Home
static om/IQuery
(query [this]
[{:menu (om/get-query Menu)}
{:footer (om/get-query Footer)}])
Object
(render [this]
...))
(def app
(compassus/application
{:routes {:index Home}
:index-route :index
:reconciler (om/reconciler
{:state {}
:parser (compassus/parser {:read read
:route-dispatch false))})}))
;; our parser won't dispatch on the `:index` key (the current route), but instead
;; on the `:menu` and `:footer` keys that are part of `Home`'s query:
(defmulti read om/dispatch)
(defmethod read :menu
[env k params]
{:value ...
:remote ...})
(defmethod read :footer
[env k params]
{:value ...
:remote ...})
Mixins
The configuration map you pass to compassus.core/application can also contain an
optional :mixins key. Its value should be a vector of mixins. Mixins hook into
the generated Compassus root component's functionality in order to extend its capabilities
or change its behavior. The currently built-in mixin constructors are:
compassus.core/wrap-render:
Constructs a mixin that will wrap all the routes in the application. It becomes
useful to specify this mixin whenever you want to define common presentation logic
for all the routes in your Compassus application. wrap-render takes a function
or an Om Next component class. The component class may or may not implement
om.next/IQuery — a query that refers to data that you want to have available to
the wrapper, e.g. the current logged in user and such.
The wrapper will be passed a map with the keys below. If the wrapper is a simple
function, the map will be passed as argument. If it is a component class, the map
will be in the component's computed props (accessible through om.next/get-computed).
If the wrapper implements om.next/IQuery, its props will be the data that the query
asks for.
- :owner - the parent component instance
- :factory - the component factory for the current route
- :props - the props for the current route.
Note: There is only supposed to be one wrap-render mixin under the :mixins
key. If there are more than one, Compassus will only use the first it finds.
Example:
;; Wrapper that doesn't implement `om.next/IQuery`
(defui Wrapper
Object
(render [this]
;; the wrapper doesn't implement `om.next/IQuery`, so the map is accessible
;; through `om.next/props`:
(let [{:keys [owner factory props]} (om/props this)]
;; implement common presentation logic for all routes
;; call the given factory with props in the end
(factory props))))
(def app
(compassus/application
{:routes ...
:reconciler (om/reconciler ...)
:mixins [(compassus/wrap-render Wrapper)]}))
;; Example of a wrapper that implements `om.next/IQuery`
(defui Wrapper
static om/IQuery
(query [this]
[:current-user])
Object
(render [this]
;; `:current-user` will be in props, the other keys will be in computed props:
(let [{:keys [current-user]} (om/props this)
{:keys [owner factory props]} (om/get-computed this)]
(dom/div nil
;; implement common presentation logic for all routes
(dom/p nil (str "Current logged in user: " current-user))
;; call the given factory with props in the end
(factory props)))))
compassus.core/will-mount:
Constructs a mixin that will hook into the componentWillMount lifecycle method
of the generated root component. Takes a function which will receive the component
as argument. Useful to perform any setup before the Compassus application mounts.
Example:
(compassus.core/will-mount
(fn [self]
;; sets a property in the state of the root component
(om/set-state! self {:foo 42})))
compassus.core/did-mount:
Constructs a mixin that will hook into the componentDidMount lifecycle method
of the generated root component. Takes a function which will receive the component
as argument. Useful to perform any setup after the Compassus application mounts.
Example:
(compassus.core/did-mount
(fn [self]
(start-analytics!)))
compassus.core/will-unmount:
Constructs a mixin that will hook into the componentWillUnmount lifecycle method
of the generated root component. Takes a function which will receive the component
as argument. Useful to perform any cleanup after the Compassus application unmounts.
Example:
(compassus.core/will-unmount
(fn [self]
(stop-analytics!)))
A note on mixins
Mixins are just data. Compassus built-in mixin constructors are just helpers around assembling this data. For example, building a mixin to hook into the Compassus root component's query could also be done as shown below:
(def app
(compassus/application
{:routes ...
:reconciler (om/reconciler ...)
:mixins [{:render MyWrapper}]}))
Utility functions
There are a few utility functions in compassus.core. Below is a description of
these functions along with simple examples of their usage.
root-class
Return the Compassus application's root class.
(compassus/root-class app)
mount!
Mount a compassus application in the DOM.
(compassus/mount! app (js/document.getElementById "app"))
get-reconciler
Get the reconciler for the Compassus application.
(compassus/get-r
