Om Next routing with om.next/set-query!
An implementation of client side routing using the client-side router library secretary and om.next/set-query!. Note: this solution may become outdated when Routing-Hooks is made available. Further reading on Om Next routing, see: Routing-Support.
Also take a look first at: Routing in Om Next — a Catalog of Approaches, which describes Om Next routing variants without third party client-side router libraries. (In fact this catalog of approaches obsoletes my article so you might as well stop reading and go the the above link directly.)
GitHub
The code for this example is on GitHub.
Implementation
(excuse my Clojure –rookie)
1(ns yourproject.app
2 (:require [om.next :as om :refer-macros [defui]]
3 [om.dom :as dom]
4 [secretary.core :as secretary]
5
6 [clojure.string :as s]
7 [yourproject.util :as util]
8
9 [yourproject.reconciler :refer [reconciler]]
10 [yourproject.parsers.app :as app-parser]
11
12 [yourproject.navbar :refer [Navbar navbar]]
13 [yourproject.pages.home :refer [HomePage home-page]]
14 [yourproject.pages.browse :refer [BrowsePage browse-page]]
15 [yourproject.pages.about :refer [AboutPage about-page]]))
16
17;;-----------
18;; Constants.
19(def pages
20 "Information on pages. Update this when new pages are added. Also
21 update the routes in the routing namespace. Beware: (a) keywords
22 *must* start with the :page+ prefix. (b) the URL /home is an alias
23 for / (under the hood) so don't define a /home entry."
24
25 {"/" [:page+home
26 (om/get-query HomePage)
27 home-page]
28 "/browse" [:page+browse
29 (om/get-query BrowsePage)
30 browse-page]
31 "/about" [:page+about
32 (om/get-query AboutPage)
33 about-page]})
34
35;;---------
36;; Queries.
37(def app-query
38 "Application level query."
39 {:app [:logged-in?]})
40
41(def navbar-query
42 "Navbar query"
43 {:navbar (om/get-query Navbar)})
44
45(defn page-query
46 "Gets query by page keyword and page subquery."
47 [kw sq]
48 {kw sq})
49
50(defn query-by-page
51 "Gets query by page."
52 [page]
53 {:pre [(not (nil? page))]
54 :post [(not (nil? %))]}
55
56 (if (contains? pages page)
57 (let [pi (get pages page)]
58 [app-query
59 navbar-query
60 (page-query (first pi) (second pi))])
61 ;; Forces post-assert fail.
62 nil))
63
64(defn page-info-by-props
65 "Gets pages element for query via props."
66 [props]
67 {:pre [(not (nil? props))]
68 :post [(not (nil? %))]}
69
70 (let [kw (first (filter #(s/starts-with? (str %) ":page+")
71 (keys props)))]
72 (if (not (nil? kw))
73 ;; Here kw has a :page+ type keyword.
74 (let [kws (str kw)
75 pg (str "/" (subs kws 6))
76 pgi (if (= pg "/home") "/" pg)]
77 (get pages pgi))
78 ;; Forces post-assert fail.
79 nil)))
80
81(defn keyword-by-props
82 "Gets keyword for query via props."
83 [props]
84 {:pre [(not (nil? props))]
85 :post [(not (nil? %))]}
86
87 (let [pi (page-info-by-props props)]
88 (if (not (nil? pi))
89 (first pi)
90 ;; Forces post-assert fail.
91 nil)))
92
93(defn factory-fcn-by-props
94 "Gets factory function for query via props."
95 [props]
96 {:pre [(not (nil? props))]
97 :post [(not (nil? %))]}
98
99 (let [pi (page-info-by-props props)]
100 (if (not (nil? pi))
101 (second (next pi))
102 ;; forces post-assert fail
103 nil)))
104
105;;------------------------
106;; Om-next root component.
107;;
108(defui App
109 static om/IQuery
110 (query [this]
111 (query-by-page "/"))
112
113 Object
114 (render [this]
115
116 (let [props (om/props this)
117 app-props (:app props)
118 {:keys [logged-in?]} app-props
119
120 navbar-props (:navbar props)
121 pkw (keyword-by-props props)
122 page-props (pkw props)]
123
124 (dom/div nil
125 (dom/h4 nil (str "*** "(if logged-in? "LOGGED IN" "LOGGED OUT") "***"))
126
127 (navbar navbar-props)
128 ((factory-fcn-by-props props) page-props)))))
129
130;;-----------------
131;; Sets page.
132;;
133(defn set-page!
134 "Sets page via an Om Next set-query call. The resulting re-render of
135 App displays the new page."
136 [page]
137 {:pre [(not (nil? page))]}
138
139 (let [root (om/app-root reconciler)]
140 (when (and (not (nil? page))
141 (not (nil? root)))
142 (let [q (query-by-page page)]
143 (om/set-query! root
144 {:query q})))))