I am having trouble swapping a value in a table. When I press the button, instead of the value being changed the whole table is removed and I can't figure out why. Below is my code. (rt refers to a reagent-table by frozenlock https://github.com/Frozenlock/reagent-table)
(ns <namespace name>
(:require [reagent.core :as reagent :refer [atom]]
[reagent-table.core :as rt]
[clojure.walk :as walk]))
(def table-data {:headers ["1" "2" "3" "4"]
:rows [["A"]]})
(defonce tdata (atom table-data))
(defn replace-value [struct]
(walk/prewalk-replace {"A" "hello"} (struct :rows)))
(defn change-value [tdata]
[:div
[:input.btn.btn-primary
{:type :submit
:on-click #(swap! tdata replace-value)
:value "Change"}]
])
(defn tablescreen []
[:div
[:div.container
[:div.span12
[rt/reagent-table tdata]
[change-value tdata]]]
])
Initally on the screen it shows the table. However, when pressing the button, I expected "A" to change to "hello". However, when pressing the button the whole table is removed from the view and only the button is left
Related
I want to get this behavior: when the button is pressed with user the button's text and the label's text should are changed together.
But the problem is button and label have the equal name of keys for the text properties. And I can't store equal keys in one hash-map.
;;I have two atoms keeps the state of button text and state of label text
(def *button-text (atom
{:text "click me"}))
(def *label-text (atom
{:text "press the button"}))
;;I have the root function which should accepts arguments for button and label props.
But these props have equal names - text - and I can't store two equal keys in one map.
{:fx/type root
:text (:text *button-text)
:text (:text *label-text)}
;;This will cause an error.
This is how I solved this problem. But is too much of the code and out of normal way.
(ns examp.core
(:gen-class)
(:require [cljfx.api :as fx])
(:import [javafx.application Platform]))
(def *button-text (atom
{:text "click me"}))
(def *label-text (atom
{:text "press the button"}))
(def renderer (fx/create-renderer))
(defn root [{:keys [one two]}]
(let [button-text (:text one)
label-text (:text two)]
{:fx/type :stage
:showing true
:title "Window"
:width 250
:height 150
:scene {:fx/type :scene
:root {:fx/type :v-box
:alignment :center
:spacing 10
:children [{:fx/type :label
:text label-text}
{:fx/type :button
:min-width 100
:min-height 50
:text button-text
:on-action (fn [_]
(if (= button-text "click me")
(do
(swap! *button-text assoc :text "clicked")
(swap! *label-text assoc :text "button is pressed")
(renderer
{:fx/type root
:one #*button-text
:two #*label-text}))
(do
(swap! *button-text assoc :text "click me")
(swap! *label-text assoc :text "presse the button")
(renderer
{:fx/type root
:one #*button-text
:two #*label-text}))))}]}}}))
(defn -main [& args]
(Platform/setImplicitExit true)
(renderer {:fx/type root
:one #*button-text
:two #*label-text}))
Before I will show you my attempt, here is the link to the official Cljfx examples repository. These examples should be useful for you, as they show practices for managing app state, event handling and so on.
For this situation, I recommend studying e05_fn_fx_like_state.clj- this is also an example I based my code on:
(ns examp.core
(:require [cljfx.api :as fx])
(:gen-class))
(def *state
(atom {:label-text "Click the button."
:button-text "Click me!"}))
(defn root [{:keys [label-text button-text]}]
{:fx/type :stage
:showing true
:title "Window"
:width 250
:height 150
:scene {:fx/type :scene
:root {:fx/type :v-box
:alignment :center
:spacing 10
:children [{:fx/type :label
:text label-text}
{:fx/type :button
:text button-text
:min-width 100
:min-height 50
:on-action {:key :button-action}}]}}})
(defn map-event-handler [event]
(when (= (:key event) :button-action)
(if (= (:button-text #*state) "Click me!")
(reset! *state {:label-text "The button was clicked!"
:button-text "Clicked!"})
(reset! *state {:label-text "Click the button."
:button-text "Click me!"}))))
(def renderer
(fx/create-renderer
:middleware (fx/wrap-map-desc root)
:opts {:fx.opt/map-event-handler map-event-handler}))
(defn -main [& args]
(fx/mount-renderer *state renderer))
Hi guys I'm new at Clojure and ClojureScript...
I'm filling out 2 select element ... What I wonna do is update the second select depending on what option the user choose in the first select.
This is my code:
(ns easy-recipe.components.calculate
(:require [reagent.core :as r :refer [atom]]
[ajax.core :as ajax]
[reagent.session :as session]
[easy-recipe.components.common :refer [input select button]]
[easy-recipe.bulma.core :refer [horizontal-select horizontal-input-has-addons table columns box]]))
(defn handler [request]
(session/put! :categories (get-in request [:body :categories]))
(session/put! :breads (get-in request [:body :breads]))
(session/put! :recipes (get-in request [:body :recipes])))
(defn error-hadler [request]
(let [errors {:server-error (get-in request [:body :erros])}]
errors))
(defn get-categories-breads-recipes []
(ajax/GET "/api/calculate"
{:handler handler
:error-hadler error-hadler}))
(defn select-fun-wrapper [breads]
(fn [e]
(let [category_value (-> e .-target .-value)]
(reset! breads
(filter
#(= category_value (str (% :category_id)))
(session/get :breads))))))
(defn calculate-page []
(get-categories-breads-recipes)
(let [fields (atom {})
categories (atom nil)
breads (atom nil)
recipe (atom nil)]
(fn []
(reset! categories (session/get :categories))
;(reset! breads (filter #(= 1 (% :category_id)) (session/get :breads)))
[:div.container
[box
[horizontal-select "Category"
[select "category" "select" #categories (select-fun-wrapper breads)]]
[horizontal-select "Bread"
[select "bread" "select" #breads #()]]
[horizontal-input-has-addons "Quantity"
[input "quantity" "input" :text "" fields]
[button "quantity-btn" "button" "Add" #() nil]]]
[box
[columns
[table ["Ingredients" "Quantity"] #recipe]
[table ["Product" " "] [["30 Panes" "x"]]]]]])))
As you have noticed the breads reset! is commented... now the "select-fun-wrapper" is working fine, it updates the bread select depening on the category option selected... but if I uncomment that line the "select-fun-wrapper" will stop working (not updating the second select)... I wonna know why does it happend?
I can not leave this line commented because right now I have the problem thar the "Bread" select starts empthy... How could I fill the bread atom without using the reset! function?
Extra code (if it makes it clear):
(ns easy-recipe.bulma.core)
(defn horizontal-select [label select]
[:div.field.is-horizontal
[:div.field-label.is-normal>label.label label]
[:div.field-body>div.field.is-narrow>div.control>div.select.is-fullwidth
select]])
....
(ns easy-recipe.components.common)
(defn select [id class options function]
[:select {:id id :class class :on-change function}
(for [opt options]
^{:key (opt :id)}
[:option {:value (opt :id)} (opt :name)])])
....
I just learn Reagent in Clojurescript, I am just following some tutorial but maybe I miss something I have this code for the state
(defonce app-state (atom {:text "Hello Chestnut!" :click-count 0}))
and the rendered view
(defn article []
[:div
[:div "The atom" [:code "click-count"] " has value : " (:click-count #app-state)]
[:input {:type "button" :value "Add"
:on-click #(swap! (:click-count #app-state) inc)}]
]
)
I'm trying to increment the state when they button is pressed, but I got this error on the console
Error: No protocol method ISwap.-swap! defined for type number: 0
the atom should be swapped not the :click-count
(swap! app-state update :click-count inc)
Here's a simple re-frame app that I tried to create based on the existing example project in re-frame's github repo. But it is only displaying things from the html file. Seems like no event is being dispatched. Can anyone point out what am I doing wrong? Thanks.
(ns simple.core
(:require [reagent.core :as reagent]
[re-frame.core :as rf]
[clojure.string :as str]))
(rf/reg-event-db
:rand
(fn [db [_ _]]
(assoc db :winner ( + 2 (rand-int 3)))))
(rf/reg-sub
:winner
(fn [db _]
(:winner db)))
(def participants ["Alice" "Bob" "Ellie"])
(defn winners-name
[idx]
(get participants idx))
(defn show-winner
[]
[:h1
(winners-name
(#(rf/subscribe [:winner])))])
(defn ui
[]
[:div
[:h1 "Lottery"]
[show-winner]])
(defn ^:export run
[]
(rf/dispatch-sync [:rand])
(reagent/render [ui]
(js/document.getElementById "app")))
The :rand handler will produce nil most times since you are adding 2 to the generated value and the participants vector only has 3 entries.
The issue is caused because of a pair of extra parenthesis around the deref thing. So the function winners-name is treating it as a list instead of an integer.
(winners-name
(#(rf/subscribe [:winner]))
I'm trying to add the following Hiccup template function to my file
(defn d3-page [title js body & {:keys [extra-js] :or {extra-js []}}]
(html5
[:head
[:title title]
(include-css "/css/nv.d3.css"))
(include-css "/css/style.css")]
[:body
(concat
[body]
[(include-js "http://d3js.org/d3.v3.min.js")
(include-js (str "https://raw.github.com"
"/novus/nvd3"
"/master/nv.d3.min.js")]
(map include-js extra-js)
[(include-js "/js/script.js")
(javascript-tag js)])]))
but keep getting an unmatched delimiter when I run lein ring server. This comes from Clojure Data Cookbook, so I am surprised to find an error and suspect the error is just on my end. Below is the rest of the code in the file:
(ns web-viz.web
(:require [compojure.route :as route]
[compojure.handler :as handler]
[clojure.string :as str])
(:use compojure.core
ring.adapter.jetty
[ring.middleware.content-type :only
(wrap-content-type)]
[ring.middleware.file :only (wrap-file)]
[ring.middleware.file-info :only
(wrap-file-info)]
[ring.middleware.stacktrace :only
(wrap-stacktrace)]
[ring.util.response :only (redirect)]
[hiccup core element page]
[hiccup.middleware :only (wrap-base-url)]))
(defn d3-page...as above
...)
(deftype Group [key values])
(deftype Point [x y size])
(defn add-label [chart axis label]
(if-not (nil? label)
(.axisLabel (aget chart axis) label)))
(defn add-axes-labels [chart x-label y-label]
(doto chart (add-label "xAxis" x-label)
(add-label "yAxis" y-label)))
(defn populate-node [selector chart groups transition continuation]
(-> (.select js/d3 selector)
(.datum groups)
(.transition)
(.duration (if transition 500 0))
(.call chart)
(.call continuation)))
(defn force-layout-plot []
(d3-page "Force-Directed Layout"
"webviz.force.force_layout();"
[:div#force.chart [:svg]]))
(defroutes site-routes
(GET "/force" [] (force-layout-plot))
(GET "/force/data.json" []
(redirect "/data/census-race.json"))
(route/resources "/")
(route/not-found "Page not found"))
(def app (-> (handler/site site-routes)))
In line 5
(include-css "/css/nv.d3.css"))
There's an extra ) there.
And in line 13,
"/master/nv.d3.min.js")]
There's one ) missing. Should be
"/master/nv.d3.min.js"))]
You should use an editor which can do the matching of braces, parentheses, and brackets, etc. automatically.