I have this structure (ordered map) in my "db" with the keyword ":questions":
{:33 {:question "one", :id 33, :answers [{:id 22, :question_id 33, :answer "one", :correct false}
{:id 4, :question_id 33, :answer "two", :correct false}]}},
{:39 {:question "two", :id 39, :answers []}},
{:41 {:question "three", :id 41, :answers [{:id 29, :question_id 41, :answer "one", :correct false}
{:id 35, :question_id 41, :answer "two", :correct true}]}}
I can add a new question in the event handler "re-frame/reg-event-db" adding:
(assoc-in db [:questions (:id response)] new-map-stuff)
but I don't know how to add a map in the ":answers" key. Besides, I'm afraid that I'm rendering all the questions every time I'm adding a new answer.
I read about the "path" interceptor (kind of "update-in"), but I can't find an example about how to use it .
You do it just like in plain clojure, using update-in
. First start at the Clojure CheatSheet:
http://jafingerhut.github.io/cheatsheet/clojuredocs/cheatsheet-tiptip-cdocs-summary.html
or the ClojureScript version: http://cljs.info
Look at the docs for update-in
: https://clojuredocs.org/clojure.core/update-in
You need 2 componenents
You didn't fully specify your data. I'm assuming it looks like this:
(def db {:questions [
{:33 {:question "one", :id 33,
:answers [{:id 22, :question_id 33, :answer "one", :correct false}
{:id 4, :question_id 33, :answer "two", :correct false}]}},
{:39 {:question "two", :id 39, :answers []}},
{:41 {:question "three", :id 41,
:answers [{:id 29, :question_id 41, :answer "one", :correct false}
{:id 35, :question_id 41, :answer "two", :correct true}]}}]})
I'll make up a new answer
map to add:
(def new-answer {:id 42, :question_id 442, :answer "The Ultimate", :correct false})
This code shows the process in pieces.
(let [submap (get-in db [:questions 0 :33 :answers])
modified (conj submap new-answer)
final-answer (update-in db [:questions 0 :33 :answers] conj new-answer) ]
First the navigation to get submap
:
submap =>
[{:id 22, :question_id 33, :answer "one", :correct false}
{:id 4, :question_id 33, :answer "two", :correct false}]
And the way you add the new answer:
modified =>
[{:id 22, :question_id 33, :answer "one", :correct false}
{:id 4, :question_id 33, :answer "two", :correct false}
{:id 42, :question_id 442, :answer "The Ultimate", :correct false}]
And putting it all together into one operation:
final-answer =>
{:questions
[{:33
{:question "one",
:id 33,
:answers
[{:id 22, :question_id 33, :answer "one", :correct false}
{:id 4, :question_id 33, :answer "two", :correct false}
{:id 42, :question_id 442, :answer "The Ultimate", :correct false}]}}
{:39 {:question "two", :id 39, :answers []}}
{:41
{:question "three",
:id 41,
:answers
[{:id 29, :question_id 41, :answer "one", :correct false}
{:id 35, :question_id 41, :answer "two", :correct true}]}}]}
All of this works identically in ClojureScript as in Clojure.
Don't worry about using the path
interceptor. I think it confuses things more than it helps. And don't worry about render speed unless:
key
metadata you can add to each list element for Reagent. See: Reagent React Clojurescript Warning: Every element in a seq should have a unique :keyUpdate
Note that submap
and modified
are shown only for demonstration purposes to show pieces of how update-in
works. The update-in
expression is the only thing you would actually include in your code. Also, note that the update-in
only uses db
and new-answer
.