Add frontend-controllers example

This commit is contained in:
Juho Teperi 2018-07-11 13:19:24 +03:00
parent 8971c8fd2b
commit 82f8aaa8cf
9 changed files with 182 additions and 16 deletions

View file

@ -0,0 +1 @@
../../../modules/reitit-core

View file

@ -0,0 +1 @@
../../../modules/reitit-frontend

View file

@ -0,0 +1 @@
../../../modules/reitit-schema

View file

@ -0,0 +1,52 @@
(defproject frontend "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.9.0"]
[ring-server "0.5.0"]
[reagent "0.8.1"]
[ring "1.6.3"]
[compojure "1.6.1"]
[hiccup "1.0.5"]
[org.clojure/clojurescript "1.10.339"]
[metosin/reitit "0.1.4-SNAPSHOT"]
[metosin/reitit-schema "0.1.4-SNAPSHOT"]
[metosin/reitit-frontend "0.1.4-SNAPSHOT"]
;; Just for pretty printting the match
[fipp "0.6.12"]]
:plugins [[lein-cljsbuild "1.1.7"]
[lein-figwheel "0.5.16"]]
:source-paths []
:resource-paths ["resources" "target/cljsbuild"]
:profiles {:dev {:dependencies [[binaryage/devtools "0.9.10"]]}}
:cljsbuild
{:builds
[{:id "app"
:figwheel true
:source-paths ["src"]
:watch-paths ["src" "checkouts/reitit-frontend/src"]
:compiler {:main "frontend.core"
:asset-path "/js/out"
:output-to "target/cljsbuild/public/js/app.js"
:output-dir "target/cljsbuild/public/js/out"
:source-map true
:optimizations :none
:pretty-print true
:preloads [devtools.preload]}}
{:id "min"
:source-paths ["src"]
:compiler {:output-to "target/cljsbuild/public/js/app.js"
:output-dir "target/cljsbuild/public/js"
:source-map "target/cljsbuild/public/js/app.js.map"
:optimizations :advanced
:pretty-print false}}]}
:figwheel {:http-server-root "public"
:server-port 3449
:nrepl-port 7002})

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Reitit frontend example</title>
</head>
<body>
<div id="app"></div>
<script src="js/app.js"></script>
</body>
</html>

View file

@ -0,0 +1,95 @@
(ns frontend.core
(:require [reagent.core :as r]
[reitit.core :as re]
[reitit.frontend :as rf]
[reitit.frontend.history :as rfh]
[reitit.frontend.controllers :as rfc]
[reitit.coercion :as rc]
[reitit.coercion.schema :as rsc]
[schema.core :as s]
[fipp.edn :as fedn]))
(defonce history (atom nil))
(defn home-page []
[:div
[:h2 "Welcome to frontend"]
[:p "Look at console log for controller calls."]])
(defn item-page [match]
(let [{:keys [path query]} (:parameters match)
{:keys [id]} path]
[:div
[:ul
[:li [:a {:href (rfh/href @history ::item {:id 1})} "Item 1"]]
[:li [:a {:href (rfh/href @history ::item {:id 2} {:foo "bar"})} "Item 2"]]]
(if id
[:h2 "Selected item " id])
(if (:foo query)
[:p "Optional foo query param: " (:foo query)])]))
(defonce match (r/atom nil))
(defn current-page []
[:div
[:ul
[:li [:a {:href (rfh/href @history ::frontpage)} "Frontpage"]]
[:li
[:a {:href (rfh/href @history ::item-list)} "Item list"]
]]
(if @match
(let [view (:view (:data @match))]
[view @match]))
[:pre (with-out-str (fedn/pprint @match))]])
(defn log-fn [& params]
(fn [_]
(apply js/console.log params)))
(def routes
(re/router
["/"
[""
{:name ::frontpage
:view home-page
:controllers [{:start (log-fn "start" "frontpage controller")
:stop (log-fn "stop" "frontpage controller")}]}]
["items"
;; Shared data for sub-routes
{:view item-page
:controllers [{:start (log-fn "start" "items controller")
:stop (log-fn "stop" "items controller")}]}
[""
{:name ::item-list
:controllers [{:start (log-fn "start" "item-list controller")
:stop (log-fn "stop" "item-list controller")}]}]
["/:id"
{:name ::item
:parameters {:path {:id s/Int}
:query {(s/optional-key :foo) s/Keyword}}
:controllers [{:params (fn [match]
(:path (:parameters match)))
:start (fn [params]
(js/console.log "start" "item controller" (:id params)))
:stop (fn [params]
(js/console.log "stop" "item controller" (:id params)))}]}]]]
{:compile rc/compile-request-coercers
:data {:controllers [{:start (log-fn "start" "root-controller")
:stop (log-fn "stop" "root controller")}]
:coercion rsc/coercion}}))
(defn init! []
(swap! history (fn [old-history]
(rfh/stop! old-history)
(rfh/start!
routes
(fn [new-match]
(swap! match (fn [old-match]
(if new-match
(assoc new-match :controllers (rfc/apply-controllers (:controllers old-match) new-match))))))
{:use-fragment true
:path-prefix "/"})))
(r/render [current-page] (.getElementById js/document "app")))
(init!)

View file

@ -8,7 +8,7 @@
[schema.core :as s] [schema.core :as s]
[fipp.edn :as fedn])) [fipp.edn :as fedn]))
(def router (atom nil)) (defonce history (atom nil))
(defn home-page [] (defn home-page []
[:div [:div
@ -19,8 +19,8 @@
[:h2 "About frontend"] [:h2 "About frontend"]
[:ul [:ul
[:li [:a {:href "http://google.com"} "external link"]] [:li [:a {:href "http://google.com"} "external link"]]
[:li [:a {:href (rfh/href @router ::foobar)} "Missing route"]] [:li [:a {:href (rfh/href @history ::foobar)} "Missing route"]]
[:li [:a {:href (rfh/href @router ::item)} "Missing route params"]]]]) [:li [:a {:href (rfh/href @history ::item)} "Missing route params"]]]])
(defn item-page [match] (defn item-page [match]
(let [{:keys [path query]} (:parameters match) (let [{:keys [path query]} (:parameters match)
@ -35,10 +35,10 @@
(defn current-page [] (defn current-page []
[:div [:div
[:ul [:ul
[:li [:a {:href (rfh/href @router ::frontpage)} "Frontpage"]] [:li [:a {:href (rfh/href @history ::frontpage)} "Frontpage"]]
[:li [:a {:href (rfh/href @router ::about)} "About"]] [:li [:a {:href (rfh/href @history ::about)} "About"]]
[:li [:a {:href (rfh/href @router ::item {:id 1})} "Item 1"]] [:li [:a {:href (rfh/href @history ::item {:id 1})} "Item 1"]]
[:li [:a {:href (rfh/href @router ::item {:id 2} {:foo "bar"})} "Item 2"]]] [:li [:a {:href (rfh/href @history ::item {:id 2} {:foo "bar"})} "Item 2"]]]
(if @match (if @match
(let [view (:view (:data @match))] (let [view (:view (:data @match))]
[view @match])) [view @match]))
@ -62,10 +62,12 @@
:data {:coercion rsc/coercion}})) :data {:coercion rsc/coercion}}))
(defn init! [] (defn init! []
(reset! router (rfh/start! routes (swap! history (fn [old-history]
(fn [m] (reset! match m)) (rfh/stop! old-history)
{:use-fragment true (rfh/start! routes
:path-prefix "/"})) (fn [m] (reset! match m))
{:use-fragment true
:path-prefix "/"})))
(r/render [current-page] (.getElementById js/document "app"))) (r/render [current-page] (.getElementById js/document "app")))
(init!) (init!)

View file

@ -22,9 +22,9 @@
those previously enabled. Resets controllers whose those previously enabled. Resets controllers whose
parameters have changed." parameters have changed."
[old-controllers new-match] [old-controllers new-match]
(let [new-controllers (map (fn [controller] (let [new-controllers (mapv (fn [controller]
(assoc controller ::params (get-params controller new-match))) (assoc controller ::params (get-params controller new-match)))
(:controllers (:data new-match))) (:controllers (:data new-match)))
changed-controllers (->> (map (fn [old new] changed-controllers (->> (map (fn [old new]
;; different controllers, or params changed ;; different controllers, or params changed
(if (not= old new) (if (not= old new)

View file

@ -57,7 +57,11 @@
(.replaceToken history (path->token history (.getPath uri))))))) (.replaceToken history (path->token history (.getPath uri)))))))
(defn start! (defn start!
"Parameters: "This registers event listeners on either haschange or HTML5 history.
When using with development workflow like Figwheel, rememeber to
remove listeners using stop! call before calling start! again.
Parameters:
- router The reitit routing tree. - router The reitit routing tree.
- on-navigate Function to be called when route changes. - on-navigate Function to be called when route changes.
@ -94,7 +98,7 @@
:close-fn (fn [] :close-fn (fn []
(e/unlistenByKey event-key) (e/unlistenByKey event-key)
(e/unlistenByKey click-listen-key) (e/unlistenByKey click-listen-key)
(.setEnabled history false))})) (.dispose history))}))
(defn stop! [{:keys [close-fn]}] (defn stop! [{:keys [close-fn]}]
(if close-fn (if close-fn