zach 2021-06-11T00:25:53.085600Z

When making forms in re-frame, what is the best way to have an initial value be based off a sub? For example, i have a shopping list with items having a default purchase quantity. e.g I buy eggs by the dozen. when i click on an item on the list, i want to put in how much of them i bought but have the default quantity value be the items' default purchase quantity.

zach 2021-06-11T00:30:01.089400Z

right now, in my db i have a list of all items, and an "active-item" which is the id of the item i just clicked on. in my subs, then, i have item-to-buy which is the all the item details for the active-item id, taken from the list of all items. i am reading through the conduit real-world app, and they have a nice pattern for forms that's something like:

(def buy-item-form
  (let [quantity (reagent/atom 1)]
  (fn [item]
      [input {:type "number" :value @quantity :on-change #(reset! quantity (-> % .-target .-value))}]
      ;; rest of the form...])))

zach 2021-06-11T00:33:48.092900Z

I tried setting the initial atom to be based off the sub, eg:

(let [item (reframe-subscribe [::subs/item-to-buy])
      quantity (reagent/atom (:default-quantity @item)])
but find that the component often initializes before that subscription has a value, and it doesn't update when i actually call the function, and so the default value is always nil. I could assign the qty value to default within the fn call, but this gets called on every change to the form, which means the value is continually being reset to the default quantity. I feel like I'm missing something, but not sure what, and hoped this chat could help. Thank you!

zach 2021-06-11T00:36:14.094300Z

in context, my ideal would be when someone clicks on eggs, the quantity value is already filled to 12, but they could change it to 6 or 18 or whatever exact amount they bought at that time.

afleck 2021-06-11T18:39:26.095Z

@webmaster601 make another sub

afleck 2021-06-11T18:43:13.097500Z

if the item map already has a default quantity assoc’d to it, you’re just going to do something like

(reg-sub ::subs/item-to-buy-default-quantity
  (fn [_qvec]
    (subscribe [::subs/item-to-buy]))
  (fn [item _qvec]
    (:default-quantity item)))

afleck 2021-06-11T18:44:26.098700Z

also i would say that idiom is to deref in the binding, so (let [item @(subscribe [::subs/item-to-buy])] …) rather than deref when you use it.

afleck 2021-06-11T18:45:09.099300Z

finally, your quantity can be in the db too! doesn’t need to be local state.

p-himik 2021-06-11T18:45:59.100Z

> that idiom is to deref in the binding Depends. It's not an idiom for form-2 or form-3 components.

afleck 2021-06-11T18:48:48.100100Z

form? are you referring to docs’ “layer”?

p-himik 2021-06-11T18:49:40.100300Z

I'm referring to Reagent view functions.

afleck 2021-06-11T18:51:37.100800Z

ah i see. why is it not idiom there?

p-himik 2021-06-11T18:52:38.101Z

Because if you deref in the outer let then a form-2 or form-3 component will not be updated when the sub changes. There are cases when you want that behavior, but it's almost never the case.

afleck 2021-06-11T18:57:41.101300Z

ahh that makes sense, thanks

afleck 2021-06-11T18:58:37.101600Z

i guess i usually put my subscribes inside the render function

zach 2021-06-11T22:37:34.102400Z

Ah, thank you for this! I think adding it to the db might be the simplest for how my app is structured. I'll give these a go!