4

I am new to clojure and reagent. I was trying to generate dynamic number of checkboxes, the state of which is stored in the app state which is a list of dicts like this

[{:checked false, :text "Sample text 1"} {:checked false, :text "Sample text 2"} {:checked false, :text "Sample text 3"}]

The function below is expected to generate a checkbox corresponding to the specified index of app's db (db). The function does it jobs and the checkboxes are clickable.

(defn gen-checkbox [index db] 
     [re-com/checkbox
            :label (:text (@db index))
            :model (:checked (@db index))
            :on-change #(swap! db assoc-in [index :checked] (not(:checked (@db index))))
     ])

However, I get this error in the browser console when I click on any checkbox.

Uncaught Error: Assert failed: Reaction is read only; on-set is not allowed

The error occurs at swap!. Can some one point out what I am doing wrong?

The db initialization part is as below:

(re-frame/reg-event-db ::initialize-db 
   (fn [_ _] 
      (atom [{:checked false :text "Sample text"}, {:checked false :text "Sample text"}, {:checked false :text "Sample text"}])
   ))

I also have a function to retreive the db. I am currently getting

(re-frame/reg-sub ::getdb 
   (fn [db]
      @db
   ))
vishnuvp
  • 283
  • 5
  • 20

1 Answers1

7

Based on the tags of your question, I presume that you are using re-frame.

You can't update the database in re-frame directly. Instead, you should register an event handler that updates the database, like the below (the exact code depends on the structure of your DB):

;; (require '[re-frame.core :as rf])

(rf/reg-event-db
 :toggle-checkbox
 (fn [db [_ index]]
   (update-in db [index :checked] not)))

And then dispatch the event in the code of your checkbox's renderer:

...
:on-change #(rf/dispatch [:toggle-checkbox index])
...
Aleph Aleph
  • 5,215
  • 2
  • 13
  • 28
  • Thanks Aleph :). However, I am hitting a new error now: No protocol method IDeref.-deref defined for type cljs.core/PersistentVector: [{:checked false, :text "Sample text"} {:checked false, :text "Sample text"} {:checked true, :text "Sample text"}] I have updated the snippet with the part of code that initializes the db as you suggested. – vishnuvp Jun 06 '18 at 05:55
  • You should make sure that you are not dereferencing your DB subscription twice. If the `db` parameter of `gen-checkbox` already contains dereferenced subscription, you should not add `@` in the function body: `... :label (:text (get db index)) :model (:checked (get db index))` – Aleph Aleph Jun 06 '18 at 21:43