Passing a Cell to a defelem Hoplon - clojurescript

Say I had the following custom textarea, how can I pass the etextarea a Cell and have both the :change and the :value work?
(defelem etextarea
[temp-cell]
(textarea :value temp-cell
:change #(reset! temp-cell #%)))
The code can be modified to include '#temp-cell' or whatever but I have tried many things and whether I pass it '(cell= cell-to-pass)' or 'cell-to-pass' it doesn't seem to work.

(defelem etextarea
[_ [temp-cell]]
(textarea :value temp-cell
:change (fn [evt]
(reset! temp-cell #evt))))

Related

Passing data between reagent components

I have the following reagent components
(defn comments-component [arg-id]
[:p arg-id])
(defn arguments-component [list-of-args]
[:ul.arguments
(for [{:keys [comment upvotes id]} #list-of-args]
^{:key id}
[:li
[:p comment]
[:p upvotes]
[:p id
[modal-button :argument
;title
"Comments"
;body
[:div
[:p "Comments"]
[comments-component id]]
;footer
[:p "OpinionNeeded"] ]]])])
(defn debate []
(let [debate-topic #(rf/subscribe [:debate/topic])
debate-affirmatives (rf/subscribe [:debate/affirmatives])
debate-negatives (rf/subscribe [:debate/negatives])]
(fn []
[:div
[:a {:href "/"} "Return home"]
[:p "This page is being worked on"]
[:div
[:h2 (get debate-topic :title)]
[:p (get debate-topic :description)]]
[:div.columns
[:div.column.is-half
[:p "Agree"]
[arguments-component debate-affirmatives]]
[:div.column.is-half
[:p "Disagree"]
[arguments-component debate-negatives]]]])))
The problem I'm encountering is that the modal button is supposed to create a modal popup with the id for each specific argument, (which I can then use to fetch the comments for that specific argument.)
But instead, I'm getting this bug whereby all the modals for different arguments show the same id.
I cannot figure out why this is happening, but it seems that all the modal-button functions are getting called with the id of the last or first argument to be rendered.
This is what the relevant portion of app-db looks like on this page
:affirmatives [{:id 1, :comment "", :upvotes 0, :topic_id 2, :affirm true} {...}]
:negatives [{:id 2, :comment "", :upvotes 0, :topic_id 2, :affirm true} {...}]
:comments [{:id 1, :comment "", :upvotes 0, :argument_id 1, :topic_id 2} {...}]
The :argument_id in each comment is a reference to the :id in the affirmatives/negatives
And here's the code that generates the modals.
(rf/reg-event-db
:app/show-modal
(fn [db [_ modal-id]]
(assoc-in db [:app/active-modals modal-id] true)))
(rf/reg-event-db
:app/hide-modal
(fn [db [_ modal-id]]
(update db :app/active-modals dissoc modal-id)))
(rf/reg-sub
:app/active-modals
(fn [db _]
(:app/active-modals db {})))
(rf/reg-sub
:app/modal-showing?
:<- [:app/active-modals]
(fn [modals [_ modal-id]]
(get modals modal-id false)))
(defn modal-card [id title body footer]
[:div.modal
{:class (when #(rf/subscribe [:app/modal-showing? id]) "is-active")}
[:div.modal-background
{:on-click #(rf/dispatch [:app/hide-modal id])}]
[:div.modal-card
[:header.modal-card-head
[:p.modal-card-title title]
[:button.delete
{:on-click #(rf/dispatch [:app/hide-modal id])}]]
[:section.modal-card-body
body]
[:footer.modal-card-foot
footer]]])
(defn modal-button [id title body footer]
[:div
[:button.button.is-primary
{:on-click #(rf/dispatch [:app/show-modal id])}
title]
[modal-card id title body footer]])
All your modals are passed the same id :argument. Thus, you always show the same modal, since the db lookup in your subscription is for :argument.
A minor tip: Following kebap-case is the recommended style in Clojure. So your app-db attributes should probably be argument-id and topic-id.
Furthermore, I would recommend subscribing debate-affirmatives and debate-negatives inside the components you pass them to. This would make them more self-containing.

How to set array as state in Reagent using ClojureScript

I'm trying to create a state called items however my code gives an error and I'm unsure of why when I try to access the items and iterate over them. What am I doing wrong here?
(def items (r/atom ["test" "test2"]))
(defn home-page []
[:div#main
[:section.section
[:h1#s-one-greeting "Hello, I'm testing"]
[:h2#s-one-greeting-two "blah blah blah"]]
[:section.section
[:p "Work history"]
[:p "yada"]
[:p "yada"]
[:ul
(for [item items]
^{:key item} [:li "item " item])]]])
You are accessing items without derefing it. So you are trying to for loop over the reagent atom which doesn't work. Just switch it to (for [item #items] ...) and you should be fine.

Select/unselect checkbox in re-frame

I'm adding a search id element to my app-db with:
[:input {:type "checkbox" :on-change #(reframe/dispatch [:add-elm {:subject_id subject-id}])}]
but I don't know how to recognize when the final user is checking or unchecking the box in order to put or withdraw the element from app-db. I want to avoid searching in the app-db to see if the element is already there.
1) Add an ID to the checkbox:
[:input {:type "checkbox" :title (:subject row-subject)
:id (str "subjects_" (:id row-subject))
:on-change #(rf/dispatch [:add-search-elm {"subjects" (:id row-subject)}])}]
2) Get and read the DOM element:
(let [ksection (first (first updates)) ;; key subject
vsection (get updates ksection) ;; value subject
elm (str ksection "_" vsection)
checkbox (gdom/getElement elm)
checked (.. checkbox -checked)]
(.log js/console (str ">>> ksection >>>>> " ksection ";; vsection >> " vsection ";; elm >> " elm " checkbox >>> " checkbox ";; checked >> " checked))

reset! on reagent atom doesn't work as intended

So what I'm trying to do is a basic tabbed view using re-com's horizontal-tabs element. I added a v-box element and below that i want to have my tabs element and the body that corresponds to the tab. although on the :on-change i call reset! on the model of the horizontal-tabs and it doesn't seem to work.
(defn left-panel []
[re-com/box
:size "auto"
:child (let [selected-tab-id (r/atom (:id (first left-panel-tabs-definition)))
change-tab #(reset! selected-tab-id %)]
[re-com/v-box
:children [[re-com/horizontal-tabs
:model selected-tab-id
:tabs left-panel-tabs-definition
:on-change change-tab]
[(left-panel-tabs #selected-tab-id)]
]])])
(defn forms-view []
[:div "Forms View"])
(defn swagger-view []
[:div "Swagger View"])
(def left-panel-tabs
{::swagger #'swagger-view
::forms #'forms-view})
(def left-panel-tabs-definition
[{:id ::forms
:label "Forms"
:say-this "Forms View"}
{:id ::swagger
:label "Swagger"
:say-this "Swagger View"}])
If instead of
[(left-panel-tabs #selected-tab-id)]
i do something like
(do (log #selected-tab-id) [(left-panel-tabs #selected-tab-id)])
it'll always print the value that i've set my reagent atom at the beginning (in this case ::forms)
Thanks to u/Galrog over at reddit I realised that in order for this to work i need to create a Form-2 component (3 forms of creating a component http://reagent-project.github.io/docs/master/CreatingReagentComponents.html#the-three-ways)
Changing my left-panel component to a Form-2 component re-renders both children on the atom's change
Code:
(defn left-panel []
(let [selected-tab-id (r/atom (:id (first left-panel-tabs-definition)))
change-tab #(reset! selected-tab-id %)]
(fn []
[re-com/box
:size "auto"
:child [re-com/v-box
:children [[re-com/horizontal-tabs
:model selected-tab-id
:tabs left-panel-tabs-definition
:on-change change-tab]
[(left-panel-tabs u/selected-tab-id)]]]])))

ClojureScript AJAX POST to send a json data

I am trying to implement AJAX POST in ClojureScript.
The following is the code i am using
(defn handler [response]
(.log js/console (str response)))
(defn test-post [name email]
(let [data {:name name :email email}]
(POST "http://localhost:5000/Add/"
{
:format {"Accept" :json}
:body (.stringify js/JSON (clj->js data))
:handler handler
:error-handler (fn [r] (prn r))
:response-format {"Content-Type" "application/json;charset=utf-8"}
}
)))
When do i call the Post method. On form Submit? Also the post request is hitting the url but the json data is not present.
I assume you're using cljs-ajax for sending data.
What you really need in something like this:
(let [data {:name name :email email}]
(POST "/Add"
{:format :json
:params data
:handler handler
:error-handler (fn [r] (prn r))})))
You can just pass a plain Clojure object as params, just set :json as data format (default is :transit).
The second question is rather open and depends on your setup. I think the simplest to use is reagent, here is a nice example with sending form data.