For example:
(defn place-background []
[:div {:class "pbackground"
:style {:height (:fullheight #app-state)}}])
(reagent/render-appendChild [place-background]
(. js/document (getElementById "container")))
because if I to use render-component it will replace the content
(ns reagenttest.core
(:require [reagent.core :as r]))
(defn sample-comp []
[:div "hello there!"])
(defn appended-container [target]
(let [id "some-unique-id"
container (.getElementById js/document id)]
(if container
container
(.appendChild target (doto (.createElement js/document "div")
(-> (.setAttribute "id" id))))
)))
(r/render [sample-comp] (appended-container (.getElementById js/document "app")))
Related
I'm having trouble sorting out why a layout/parent component (app.components.layout) is not resolving after a hard reload BUT is okay after a hot reload with dev server after I introduced routes.
The error: TypeError: dapp.components.layout.render is not a function
This error doesn't appear when I render the view component in the #match atom directly.
(ns app.views
(:require
[reagent.core :as r]
[reitit.frontend :as rf]
[reitit.coercion.schema :as rsc]
[dapp.components.layout :as layout]
[dapp.components.dashboard :as dashboard]
[dapp.components.settings :as settings])))
(def routes
(rf/router
["/"
[""
{:name ::dashboard
:view dashboard/render
:controllers [{:start (log-fn "start" "dashboad controller")
:stop (log-fn "stop" "dashboard controller")}]}]
["settings"
{:name ::settings
:view settings/render}]]
{:data {:controllers [{:start (log-fn "start" "root-controller")
:stop (log-fn "stop" "root controller")}]
:coercion rsc/coercion}}))
;; broken on a hard browser refresh but works when shadow does a hot reload.
(defn main-panel []
[:div
(if #match
(let [view (:view (:data #match))]
(layout/render view #match)))]) ;; TypeError: app.components.layout.render is not a function
;; working
(defn main-panel []
[:div
(if #match
(let [view (:view (:data #match))]
(view nil))])
Layout Component:
(ns app.components.layout)
(defn render [view match]
[:div
[view]])
View Component:
(ns app.components.dashboard)
(defn render [props]
[:div
"Dashboard"])
Setup:
(ns app.core
(:require
[reagent.dom :as rdom]
[re-frame.core :as re-frame]
[reitit.frontend.easy :as rfe]
[reitit.frontend.controllers :as rfc]
[dapp.events :as events]
[dapp.views :as views]
[dapp.config :as config]
))
(defn dev-setup []
(when config/debug?
(println "dev mode")))
(defn ^:dev/after-load mount-root []
(re-frame/clear-subscription-cache!)
(let [root-el (.getElementById js/document "app")]
(rdom/unmount-component-at-node root-el)
(rdom/render [views/main-panel] root-el)))
(defn init []
(re-frame/dispatch-sync [::events/initialize-db])
(dev-setup)
;; router setup
(rfe/start!
views/routes
(fn [new-match]
(swap! views/match (fn [old-match]
(if new-match
(assoc new-match :controllers (rfc/apply-controllers (:controllers old-match) new-match))))))
{:use-fragment true})
(mount-root))
I've written a small experimental application in Fulcro "2.6.0-RC8". If you run it you will see that the writing underneath the picture of the kitten - "Description for the card" is red. This is good - things are working. However the two buttons below the picture of the kitten should not look the same, but look identical apart from the text. The "Press primary" button should have its text in white and its background should be red. What am I doing wrong?
(ns applets.reakit-test.core
(:require [fulcro.client :as fc]
[fulcro.incubator.ui.reakit :as rk]
[fulcro.client.primitives :as prim :refer [defsc]]
[fulcro-css.css-injection :as injection]
[fulcro.client.dom :as dom]))
(def red "#FF0000")
(defsc PrimaryButton [_ {:keys [text]}]
{:query [:text]
:initial-state (fn [p] {:text p})
:css [[:.primary
{:background-color red
:border "none"
:color "white"}]]}
(rk/button :.primary text))
(def primary-button-ui (prim/factory PrimaryButton))
(defsc Experiment [_ {:keys [but-primary]}]
{:query [:but-primary (prim/get-query PrimaryButton)]
:ident (fn [] [:experiment/by-id :singleton])
:initial-state {:but-primary (prim/get-initial-state PrimaryButton "Press primary")}
:css [[:.container
{:margin "10px"}]
[:.head
{:color "#222"
:font-weight "bold"}]
[:.copy
{:color red}]]}
(dom/div
(rk/card :.container
(rk/heading :.head {:as "h3"} "Card Heading")
(rk/image {:src "https://placekitten.com/180/300" :alt "Kitten" :width 180 :height 300})
(rk/paragraph :.copy "Description for the card")
(rk/shadow))
(dom/div
(rk/button "Ordinary button")
(primary-button-ui but-primary))))
(def experiment-ui (prim/factory Experiment))
(defsc ReakitTestRoot [this {:keys [application ui/react-key]}]
{:query [:ui/react-key {:application (prim/get-query Experiment)}]
:initial-state (fn [_] {:application (prim/get-initial-state Experiment nil)
:ui/react-key "initial"})}
(dom/div {:key react-key}
(injection/style-element {:component this
:react-key react-key})
(experiment-ui application)))
(defonce app (atom nil))
(defn mount []
(reset! app (fc/mount #app ReakitTestRoot "app")))
(defn ^:export init [_]
(reset! app (fc/new-fulcro-client
:reconciler-options {:render-mode :keyframe}))
(mount))
Your query in the component Experiment is wrong. It should be a join: [{:but-primary (prim/get-query PrimaryButton)}]
I am currently learning reagent with secretary as its route. I find that I can use query-params to get a hash-map of all parameters with question mark (?) like ?name=Daniel
(ns feampersanda.core
(:require-macros [secretary.core :refer [defroute]])
(:import goog.History)
(:require
[secretary.core :as secretary]
[goog.events :as events]
[goog.history.EventType :as EventType]
[reagent.core :as r]))
;; ------------------------------
;; States
;; page --> is occupied by page state
(def app-state (r/atom {:params {}}))
;; ------------------------------
;; History
(defn hook-browser-navigation! []
(doto (History.)
(events/listen
EventType/NAVIGATE
(fn [event]
(secretary/dispatch! (.-token event))))
(.setEnabled true)))
;; -------------------------
;; Views
;; -------------------------
;; Parameters
(defn update-query-params! [query-params]
(do
(js/console.log (str query-params))
(swap! app-state assoc-in [:params :query] query-params))
)
;; -------------------------
;; Routing Config
(defn app-routes []
(secretary/set-config! :prefix "#")
(defroute "/" [query-params]
(do
(update-query-params! query-params)
(swap! app-state assoc :page :home)))
(defroute "/about/:id" [id query-params]
(do
(js/console.log id)
(update-query-params! query-params)
(swap! app-state assoc :page :about)))
(hook-browser-navigation!))
(defmulti current-page #(#app-state :page))
(defmethod current-page :home []
[:div [:h1 (str "Home Page")]
[:a {:href "#/about"} "about page"]
[:br]
[:a {:href "#/about"} (str (:count #app-state))]
])
(defmethod current-page :about []
[:div [:h1 "About Page"]
[:a {:href "#/"} (str "home page" " --> "
(:yes (:query (:params #app-state)))
)]])
(defmethod current-page :default []
[:div
[:p "404"]
])
;; -------------------------
;; Initialize app
(defn mount-root []
(app-routes)
(r/render [current-page] (.getElementById js/document "app")))
(defn init! []
(mount-root))
I don't know how to pass the id parameter to a defmethod, so I want it to be saved inside an atom, so I wonder how to get hash-map which is include all of the named parameters like http://0.0.0.0:3449/#/about/black/12 to {:path "black" :id "12"}
One solution would be to use cemerick's URL library
(require '[cemerick.url :as url])
(keys (:query (url/url (-> js/window .-location .-href))))
https://github.com/cemerick/url
I am trying to use ReactBootstrap's Modal component in a Reagent application but get a "Cannot read property 'findDOMNode' of undefined" error when attempting to show the modal.
I have [cljsjs/react-bootstrap "0.28.1-1"] as a dependency in my project.
Here is the source that I used to test with:
(ns react-bootstrap-test.core
(:require
[reagent.core :as r]
cljsjs.react-bootstrap))
(def rbutton (r/adapt-react-class js/ReactBootstrap.Button))
(def rmodal (r/adapt-react-class js/ReactBootstrap.Modal))
(def modal-header (r/adapt-react-class js/ReactBootstrap.Modal.Header))
(def modal-title (r/adapt-react-class js/ReactBootstrap.Modal.Title))
(def modal-body (r/adapt-react-class js/ReactBootstrap.Modal.Body))
(defonce show-modal (r/atom false))
(defn modal-test []
[:div
[rbutton {:bsStyle "primary"
:bsSize "large"
:active true
:on-click (fn [e]
(reset! show-modal true)
(.stopPropagation e))}
"Show Modal"]
[:div.rmodal
[rmodal {:show #show-modal}
[modal-header
[modal-title "Title"]]
[modal-body
[:h3 "Body"]]]]])
(r/render-component [modal-test]
(. js/document (getElementById "app")))
(ns ^:figwheel-always refs-test.core
(:require [om.core :as om :include-macros true]
[om.dom :as dom :include-macros true]
[sablono.core :as html :refer-macros [html]]))
(enable-console-print!)
(def app-state
(atom {:items [{:text "cat"}
{:text "dog"}
{:text "bird"}]
:selected-item {}}))
(defn selected-item []
(om/ref-cursor (:selected-item (om/root-cursor app-state))))
(defn
selected-item-title
[_ owner]
(reify
om/IRender
(render [_]
(html
[:div
(let [selected (om/observe owner (selected-item))]
(if (empty? selected)
[:h1 "Nothing selected"]
[:h1 (:text selected)]))]))))
(defn
selected-item-button
[item owner]
(reify
om/IRender
(render [_]
(html
[:li
[:button {:on-click
(fn []
(om/update! (om/root-cursor app-state) :selected-item item) ;; this doesn't update
;;(om/update! (om/root-cursor app-state) :selected-item (merge item {:foo 1})) ;; this does
)} (:text item)]]))))
(defn
root
[cursor owner]
(reify
om/IRender
(render [_]
(html
[:div
(om/build selected-item-title {})
[:ul
(om/build-all selected-item-button (:items cursor))]]))))
(om/root root app-state
{:target (.getElementById js/document "app")})
(https://www.refheap.com/108491)
The (selected-item) function crerates a ref-cursor which tracks the :selected-item key in app-state. When you click a selected-item-button the title changes to reflect the new value that has been put into the map. However, this only works once. Pressing a different button does not cause the title to re-render again so the title is always stuck at the value of the first button you pressed.
Although, simply adding a merge with an additional keyword seems to make it work... (merging with an empty map doesn't work either, tried that!)
Is my understanding on ref cursors wrong?
So, the issue was very simple.
(om/update! (om/root-cursor app-state) :selected-item item)
should have been
(om/update! (om/root-cursor app-state) :selected-item #item)
Notice the item, because it's a cursor, is dereferenced.