Last active
March 22, 2016 11:56
-
-
Save petterik/4a80bd5ecba37ed1ea71 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns navigation.example | |
(:require-macros [natal-shell.components :refer [navigator]] | |
[navigation.macros :refer [with-om-vars]]) | |
(:require [om.next :as om])) | |
;;; Helpers for getting a deep ref | |
(defn react-ref | |
"Wrapper around react-ref to always turn keywords into strings." | |
[component ref] | |
{:pre [(or (keyword? ref) (string? ref))]} | |
(om/react-ref component (cond-> ref (keyword? ref) str))) | |
(defn get-ref-in | |
"Gets react ref in components. Like get-in, but with a component | |
instead of a map and refs instead of keys. Returns nil if no ref | |
was found. | |
Keywords are casted to strings with str." | |
[component refs] | |
{:pre [(or (nil? refs) (sequential? refs))]} | |
(if-let [ref (and component (first refs))] | |
(recur (react-ref component ref) (next refs)) | |
component)) | |
(defn subquery-in | |
"Like om/subquery, but can traverse refs like (get-in m [k1 ... kn]). | |
Defaults to om/get-query of subquery-class if 'x' component is mounted." | |
[x refs subquery-class] | |
{:pre [(every? #(or (keyword? %) (string? %)) refs) | |
(fn? subquery-class)]} | |
(if (and (om/component? x) (om/mounted? x)) | |
(om/get-query (get-ref-in x refs)) | |
(and (om/iquery? subquery-class) | |
(om/get-query subquery-class)))) | |
;;; Routes | |
(def app-route->ui | |
{:login {:class Login | |
:factory (om/factory Login)} | |
:app {:class Main | |
:factory (om/factory Main)}}) | |
(defn props->route [props] | |
(or (:app/route props) :login)) | |
;;; Root component | |
(defui ^:once App | |
static om/IQuery | |
(query [this] | |
;; This query is inspired by the subquery example in: | |
;; http://anmonteiro.com/2016/02/routing-in-om-next-a-catalog-of-approaches/ | |
;; But since we've got a navigator between our om.next component | |
;; and this component (App), we'll have to go through the navigator's | |
;; refs to find our om.next component. See: subquery-in. | |
(let [route (props->route (when (om/component? this) (om/props this))) | |
static-query (get-in app-route->ui [route :class]) | |
;; The navigator will contain the ref to the component which we'll | |
;; want to subquery. | |
subquery (subquery-in this [:nav route] static-query) | |
query (cond-> [:app/route] | |
(some? subquery) | |
(conj {:route/data subquery}))] | |
query)) | |
Object | |
(render-scene [this _ _] | |
(with-om-vars | |
this | |
(let [props (om/props this) | |
route (props->route props) | |
factory (get-in app-route->ui [route :factory])] | |
;; Associate the component with the route | |
(factory (-> props :route/data (assoc :ref route))))) | |
(render [this] | |
;; Wraps the keyword in a string, since (clj->js {:key :val}) => #js {:key "val"} | |
;; and the ref needs to be ":nav" to work nicely with the rest of the code. | |
(navigator {:ref (str :nav) | |
:renderScene #(.render-scene this %1 %2)}))) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns navigation.macros | |
(:require [om.next :as om])) | |
;; Inspired by | |
;; https://github.com/hugoduncan/navigator-repro/blob/master/src/navigator_repro/macros.clj | |
(defmacro with-om-vars | |
"Returns the body of (render [this] ... ) which contains bindings | |
for various om.next dynamic vars, which is needed when calling | |
functions returned by (om/factory Class). | |
This macro allows us to create components outside the render function." | |
[component & body] | |
(let [render-with-bindings (get-in om/reshape-map [:reshape 'render]) | |
[_ [this-sym] render-body] (render-with-bindings | |
`(~'render [~'this] | |
~@body))] | |
`(let [~this-sym ~component] | |
~render-body))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment