Search code examples
swapclojurescriptreagent

How to update a reagent atom filtering in a nested vector of maps in Clojure


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))

Solution

  • 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)