Reputation: 177
Let's say I have a reagent atom with a vector of maps like this:
(def my-atom (reagent/atom {:id 256
:name "some name"
:lines [{:code "ab43" :name "first nested name" :quantity 4}
{:code "bc22" :name "second nested name" :quantity 1}
{:code "lu32" :name "third nested name" :quantity 1}}] }))
How can I update the value of a key :quantity at a certain vector nested index, for example: update line with code "bc22" to 10 quantity.
This need to filter to get the index of vector, but haven't the index because filter by "code":
(swap! my-atom assoc-in [:lines 1 :quantity] 10)
I can find with filter, but I can't swap! quantity:
(->> (:lines @my-atom)
(filter #(= (:code %) "bc22")
first))
Upvotes: 0
Views: 399
Reputation: 864
You've got options here. You could look up the index of the item, you could map over the list, updating only the item your interested in.
Depending on the specifics of the situation, you could also look at either storing the index of the element when the component is rendered, or instead build a set of cursors which are passed to your component. In that case you simply update he cursor like you would an atom, at it handles updating the backing atom efficiently.
Personally, I look at this and wonder if you are using the correct data structure in the first place. It seems probable that code
is a natural key here, especially since you are looking to update a line based on it. Perhaps a map with code
as the key and the full line as the value would make more sense. This also makes certain undesirable situations impossible (e.x. multiple lines with the same code
). Of course you'd lose ordering (unless you re-established it somehow), which may or may not be an issue.
Upvotes: 0
Reputation: 362
You can stick with the use of assoc-in
but to do so, you have to retrieve the index associated to a given code from the vector of the :lines
field in some way.
For example, I would a helper function:
(defn code->index [data code]
(->> data
:lines
(map-indexed (fn [i v] [i v]))
(filter (fn [[_ v]] (= (:code v) code)))
ffirst))
;; (code->index @my-atom "bc22")
;; => 1
And then use it in the swap:
(swap! my-atom assoc-in [:lines (code->index @my-atom "bc22") :quantity] 10)
Upvotes: 2
Reputation: 16035
(require
'[com.rpl.specter :as s])
(let [*a (atom {:id 256
:name "some name"
:lines [{:code "ab43" :name "first nested name" :quantity 4}
{:code "bc22" :name "second nested name" :quantity 1}
{:code "lu32" :name "third nested name" :quantity 1}]})]
(s/setval [s/ATOM :lines s/ALL #(-> % :code (= "bc22")) :quantity] 10 *a))
Upvotes: 1