Fork me on GitHub
#fulcro
<
2021-07-26
>
genekim00:07:00

I’m trying to delete [:trello-card/id "5a0f9851615fa324ca46ec7e"] from ident [:trello-list/id "5b1b3a29d7ce069c0b61ba6c" :trello-cards]. But when I do this, nothing happens — I expected the trello-card/id to be deleted from the table (and of course, the element to be removed from the DOM). Trying to figure out what I’m doing wrong… Thx in advance!

(swap! state merge/remove-ident* [:trello-card/id "5a0f9851615fa324ca46ec7e"]
       [:trello-list/id "5b1b3a29d7ce069c0b61ba6c" :trello-list/cards])
PS: if I can get this working, I feel like I’ll have learned how to do 80% of what I need to do in Fulcro! (I’ve learned how to load data from queries, render them, update them, and hopefully soon, delete items.)

nivekuil00:07:04

it looks like :trello-list/cards is denormalized; it should be a vec like [[:trello-card/id "abc"] ...], aka edges to idents like [:trello-card/id "abc"]. what does your trello-card component look like, and how are you loading that data?

nivekuil00:07:10

IOW an ident is a place to which data is loaded. an edge is a pointer to that place. right now it looks like you've got the data itself under that attribute instead of a vec of pointers

genekim05:07:20

Huh…. I see what you’re saying about the shape of trello-list/cards not being right. Not sure what’s happening — it’s loaded in by this:

(comp/defsc Card [this {:trello-card/keys [id dateLastActivity idList idBoard
                                           pos name desc due]
                        :as props}]
  {:query [:trello-card/id :trello-card/dateLastActivity :trello-card/idList :trello-card/idBoard
           :trello-card/pos :trello-card/name :trello-card/desc :trello-card/due]
   :ident :trello-card/id}
)

genekim05:07:02

Which is loaded in via this component: SelectedListCards:

(comp/defsc SelectedListCards [_ {:trello-list/keys [id name cards]
                                  :as                    props}
                               {:keys [on-select selected]}]
  {:query [:trello-list/id :trello-list/name :trello-list/cards]
   :ident (fn [x] [:component/id ::SelectedListCards])}

genekim05:07:06

Oh!!! The problem is right there in the :query for SelectedListCards! It’s missing the comp/get-query. This works! Thank you @U797MAJ8M!!

kardan07:07:38

Yay, now you’re at 80% - celebrate. I’m about to dig into Fulcro like you and enjoy your comments along the way.

Jakub Holý (HolyJak)12:07:38

If you use Card inside the SelectedCardList then https://github.com/holyjak/fulcro-troubleshooting would have warned you about the omission, I think

genekim18:07:08

Yes, indeed, @holyjak! I used your fantastic guide to zero in on the problem! Thank you!

Jakub Holý (HolyJak)18:07:55

Good to hear, though in this case I didn't mean the guide but the tool (of the, confusingly, same name) :)

genekim18:07:37

Which gets me to the other thing I noticed — also diagnosed using @holyjak’s fantastic guide. When I click a button to call the mutation that calls remove-entity, the UI updates. Hooray. But when I manually call the function in a REPL that does the remove-entity (which the mutation calls), the updated DB shows up in Fulcro Inspector, but the UI doesn’t change. ??? As @holyjak recommends, when I call force-render!, the UI updates. I’m trying to figure out who the UI doesn’t update w/o that force-render!… (Part of me doesn’t care, but I feel like I need to understand this to truly understand the Fulcro way. 🙂

Jakub Holý (HolyJak)19:07:08

I think that when you transact! (unless you transact!! ) then Fulcro schedules a render afterwards. Could that be it?

sheluchin17:07:41

I'm working through the Fulcro Exercises and 6 Client-side mutations is throwing up a warning in my console when I either Select All -> Delete or manually select each player on a team and delete them all:

react_devtools_backend.js:2574 Warning: A component is changing a controlled input to be uncontrolled. This is likely
caused by the value changing from a defined to undefined, which should not happen. Decide between using a controlled or
uncontrolled input element for the lifetime of the component. More info: 
    at input
    at ctor ()
    at label
    at div
    at holyjak.fulcro-exercises/Team
    at form
    at holyjak.fulcro-exercises/Root6
It looks like the solutions also raise the same warning. Is this warning something I should be concerned about and need to understand better?

2
Jakub Holý (HolyJak)17:07:00

Thank you! I'm not sure how serious problem this causes to React. We have somewhere nil where we should instead have a value such as false. I'll have a look.

🙏 2
Oleh K.19:07:52

Hello, guys, please help. I'm using RAD and added simple defsc component. But I don't understand how to feed props in it.

(defmutation bump-number [ignored]
  (action [{:keys [state]}]
          (swap! state update :ui/number inc)))

(defsc Rom [this {:ui/keys [number] :as props}]
  {:query         [:ui/number]
   :initial-state {:ui/number 5}
   :ident               (fn [] [:component/id ::Rom])}
  (dom/div
   (dom/h4 "This is an example.")
   (dom/button {:onClick #(comp/transact! this [(bump-number {})])}
               "You've clicked this button " number " times.")))

tony.kay20:07:52

I know the others have answered your question, but just an add. I can tell from the code you posted that you have not yet understood the tree of initial state and how props are fed to the UI. The way I can tell this is you said nothing about how the component is composed into the app. A lot of people have this misconception. Standard Fulcro components are normalized and easily refactored, but they are not stand-alone. They must be composed into their parent correctly. This is the #1 misunderstanding (about 95% of problems people have is with this misunderstanding). The data for a component ends up AT the ident in the db, which is how they can tell that your mutation is wrong (swaps in mutations will almost always be a swap on an update-in of a path of length 3 (the ident is 2, and the prop you want to change has a name, which makes 3).

tony.kay20:07:12

Try reviewing the basic materials in the YouTube video..if you haven't yet watched those

tony.kay20:07:32

Another quick note: If you transact! on this (the component), then the env of the mutation will include ref , which will be the ident of the component that invoked the mutation. That is how general mutations like m/set-value! are written.

Oleh K.14:07:06

Thank you @U0CKQ19AQ !, I have fixed it. The main problem for me was to understand that I should `collect`  initial state from children in the root component and then to feed `props`  to children

Oleh K.19:07:36

It doesn't display initial number and doesn't display incremented ones. But I can see in Fulcro Inspect changing of ui/number

Jakub Holý (HolyJak)19:07:38

I think you read and write at different places. You mutations sets DB -> :ui/number while the component reads DB -> :component/id -> ::Rom -> :ui/number . Check again the sections on idents and normalization, perhaps.

genekim20:07:00

I had trouble with the same thing — check out how I was able to implement this in the RAD template here: https://github.com/realgenekim/rss-reader-fulcro-demo/blob/gene-stories/src/shared/com/example/ui/button_toys_form.cljc#L18 I think the problem is the ident in your bump-number — the ident should be [:component/id ::Rom :ui/number]. Right now, you’re incrementing something outside of the “lexical scope” of the Rom component. (Exactly the same mistake I made, before talking with @U0CKQ19AQ.) (I see now that I’m saying exactly the same thing as @holyjak is. 🙂

Jakub Holý (HolyJak)20:07:57

Noteworthy - there are better solutions than a dedicated mutation, namely https://cljdoc.org/d/com.fulcrologic/fulcro/3.5.1/api/com.fulcrologic.fulcro.mutations#set-integer! (beware - just call it, do not wrap in transact). This will ensure you change the right place. See its impl.

Oleh K.14:07:41

Thank you guys! I have fixed it. The main problem for me was to understand that I should collect initial state from children in the root component and then to feed props to children

Jakub Holý (HolyJak)16:07:12

If you have ant tips how to make that easier to understand in the https://fulcro-community.github.io/guides/tutorial-minimalist-fulcro/index.html, pls let me know! This is essential.

Oleh K.07:07:48

I didn’t even know about this mini-guide, I need to read it first, thank you for the link

👍 3
Jakub Holý (HolyJak)13:07:44

BTW, we're you aware of the Fulcro Community site? If not then how to make it more visible?

Oleh K.19:07:57

As I see now there is the link in the Fulcro book at the beginning. But I rarely look at that section, I look at the left content navigation part for particular things. So maybe it would be useful if there would be a section, for example, "Useful links" or "Other tutorials" or even directly "Fulcro Community Site" (And in the Fulcro RAD book as well). Also I think the problem is that "googling" "fulcro" doesn't show the community web site at first page.

❤️ 3
genekim19:07:39

Thanks for all the help getting entity deletion working! Which gets me to the other thing I noticed — also partially diagnosed using @holyjak’s fantastic guide. When I click a button to call the mutation that calls `remove-entity`, the UI updates.  Hooray. But when I manually call the function in a REPL that does the  `remove-entity` (which the mutation calls), the updated DB shows up in Fulcro Inspector, but the UI doesn’t change.  ??? As @holyjak recommends, when I call `force-render!`, the UI updates. I’m trying to figure out who the UI doesn’t update w/o that `force-render!`…  (Part of me doesn’t care, but I feel like I need to understand this to truly understand the Fulcro way.  🙂

tony.kay20:07:50

Fulcro does NOT watch the db atom (Inspect does). Fulcro is a strict transactional system. If you don't run a transaction, as far as it is concerned there is no UI to update.

tony.kay20:07:44

So, if you want to run something in the REPL, the thing you want to run is transact!, or something that wraps it (as does load!, merge-component!, set-value!, etc. Everything you call that changes something to do with the state db in Fulcro results in a transaction underneath...just trace the source and you'll quickly reach where it is doing a transact. load! for example, defines an internal-load mutation and when you call load! it submits a transact on internal-load.

genekim20:07:30

https://clojurians.slack.com/archives/C68M60S4F/p1627327328105600?thread_ts=1627258680.097100&amp;cid=C68M60S4F Oh, that’s interesting! From Fulcro book: “comp/transact! The central function for running abstract (possibly full-stack) changes in the application. Can be run with a component or app. If run with the app, will typically cause a root re-render.” Huh. I now see that merge! doesn’t force render, either. Just comp/transact!. And df/load!, too, right? (ah, thanks for answer — `load!` forces a transaction.) THANKS!!! Another Fulcro mystery solved.

tony.kay20:07:26

merge! should be a transact! as well.

tony.kay20:07:44

oh...no, it isn't

tony.kay20:07:36

ooops. That's right. Some of the merge functions are meant to be used as utilities within a mutation.

tony.kay20:07:10

merge! isn't really meant for public use...it's a very old function that was part of the original implementation mixed with Om Next, and I could not remove it without breaking external code (because it was public). So, even though I didn't really want it to be public still, I was stuck doing so because I don't like to break existing code if at all possible. It does not hurt anything, but as you noted it does not force a render. These functions are part of the implementation of the load logic (which is already running in a mutation) which is why they are not, themselves, written as transactions.

tony.kay20:07:26

The ! versions should probably all schedule a render.

genekim21:07:50

FWIW, that sounds like a great change, and hopefully harmless — it was a bit puzzling to not see the re-render. Thx!!!

tony.kay02:07:07

Pushed as Fulcro 3.5.2

genekim16:07:25

Woot! Delightful! Thank you!