fulcro

Book: http://book.fulcrologic.com, Community Resources: https://fulcro-community.github.io/, RAD book at http://book.fulcrologic.com/RAD.html
Björn Ebbinghaus 2021-01-12T00:34:09.301900Z

When you say: > It has to [..] know about children and > parents are very very often forced to have knowledge of their children Do you mean that in a sense, that they are just aware of their existence and/or relationship? Or do you mean that in a practical sense that they know about the query and props a child has? --------------------------------------------- So I renamed the component to ProcessContext and pulled out the Process related stuff into a new component ProcessOutline and changed the ident of the component. Is that what you had in mind?

(defsc ProcessOutline [_ _]
 {:query [::process/slug ::process/title ::process/description]
  :ident ::process/slug}
 (dom/a {:href (str "/decision/" slug "/home")} "Back to home!"))
(def ui-process-outline (comp/factory ProcessOutline)

(defsc ProcessContext [_ {:ui/keys [process-router new-proposal-modal] :keys [process-outline]}]
 {:query [::process/slug 
          {:process-outline (comp/get-query ProcessOutline)}
          {:ui/process-router (comp/get-query ProcessRouter)}
          {:ui/new-proposal-modal (comp/get-query ProposalModal)}]
  :ident [:process-context ::process/slug]
  :route-segment ["decision" ::process/slug]
  :will-enter (fn [app {slug ::process/slug}]
                (let [ident (comp/get-ident ProcessContext {::process/slug slug})]
                  (dr/route-deferred ident
                    (fn []
                      (df/load! app [::process/slug slug] ProcessOutline
                        {:target (targeting/replace-at (conj ident :process-outline))})
                      (mrg/merge-component! app ProcessContext (comp/get-initial-state ProcessContext {:slug slug}))
                      (dr/target-ready! app ident)))))}
 (comp/fragment
   (ui-process-outline process-outline)
   (ui-global-add-proposal-to-process-modal new-proposal-modal)
   (ui-process-router process-router)))

tony.kay 2021-01-12T01:51:19.302300Z

It’s your program, I’m not sure what you’re thinking. I was just expressing that it makes little sense to me for the identity of a specific parent to be identical to a specific child of that same parent. “I am my own grandpa” is not a good structure. If you have a desire to split duties of rendering that can be done with functions. If the parent is being given the slug because you want to show it in the parent, why not just pull the slug out of the child props?

Gleb Posobin 2021-01-12T02:29:34.302500Z

Calling change-route! from a state machine is okay (it even appears in the example app I believe), but the problem is that the state machine now needs to know about that router, which is not even the main router, but only for that specific page.

Gleb Posobin 2021-01-12T02:31:02.302700Z

I am sure I will need this again in the future, so the session state machine will become more and more intertwined with other components sounds like.

tony.kay 2021-01-12T02:56:35.303Z

Your idea of using an alt table is sorta “customized denormalized normalization”…

Gleb Posobin 2021-01-12T06:07:39.303200Z

Ah, no, looks like I shouldn't do anything non-pure from a UISM =/ I think I should be able to trigger the route! event of the main page router's state machine from the session state machine but I have killed the past two hours trying to figure out how to make that work already.

Jakub Holý 2021-01-12T07:58:50.303500Z

The main Fulcro site still recommends starting with plain Fulcro. But you can give RAD try too.

Jakub Holý 2021-01-12T07:59:34.303700Z

https://github.com/fulcro-community/awesome-fulcro has also a number of useful learning resources

1👍
Gleb Posobin 2021-01-12T08:28:17.305300Z

What could be a reason for

dr/target-ready! was called but there was no router waiting for the target listed:  [:component/id :main] This could mean you sent one ident, and indicated ready on another.
This happens in will-enter that looks like:
:will-enter
   (fn [app _path-params]
     (dr/route-deferred [:component/id :main]
       (fn []
         (comp/transact! app
           [(dr/target-ready {:target [:component/id :main]})
            (uism/trigger-state-machine-event
              {::uism/event-id :event/opened-home-page
               ::uism/asm-id   ::main-page-machine})]))))
How do I solve that? The ident looks correct to me.

Björn Ebbinghaus 2021-01-12T14:35:57.305700Z

Hm… I thought using the props of a child was kind of bad, because it is misusing the colocation aspect. What happens, when the query of your child changes? That would break the parent. That’s the motivation behind my recent question about an “anonymous component”. > Your idea of using an alt table is sorta “customized denormalized normalization”… How would I compose it otherwise? I don’t want to load! :process-context as it isn’t the concern of the backend to know about this. I have to do it manual, right?

Gleb Posobin 2021-01-12T14:48:57.305900Z

I shouldn't have called transact! inside route-deferred: the app it is using is not updated with taking the route-deferred into account: it is captured from before the route-deferred is called. So I had to make a new mutation and transact! it first: the mutation will get the updated app when it executes. Why doesn't route-deferred accept an app argument?

Björn Ebbinghaus 2021-01-12T15:26:05.306400Z

Ok, no, not using the props of children is stupid... You need to work with them when you do any kind of filtering or sorting, or similar. 😕

henrik 2021-01-12T16:46:42.307300Z

If anyone is interested, we just released a small wrapper library for heroicons (from Tailwind CSS): https://github.com/backminds/heroicons-clojure

1👏2🚀
avocade 2021-01-12T16:48:32.307500Z

Pretty nice to quickly get going with using the awesome heroicons set. Btw, TailwindCSS (and UI) is a dream to use, if anyone is new to it: https://tailwindcss.com

tvaughan 2021-01-12T17:16:08.307900Z

Second this. Tailwind has been awesome

1👍
Jakub Holý 2021-01-12T17:17:32.308100Z

The code snippet looks ok to me. What is the state of the router / what do the transactions show that happened? Both the book and my routers do transact! on the app passed to will enter and we don't have any problems with that. Why do you?

tony.kay 2021-01-12T17:25:26.308500Z

Yep. Parents always need to know something about their children. It is the reverse that is more of a problem, because the parent context is usually a mystery, so to get things from a parent we always provide things like callbacks and published API of the child so the parent can “black box” discover it. It’s couping, but it’s one-way and well-defined. The parent also needs to know the query of the child (it has to compose it in). That is a grey area because you are right, it doesn’t need to know the content of the query…unless it is a TodoList where “check all” state comes from looking at the children, or your case, where you want to know the slug. It is just the way it is. You don’t want to define a new prop or query to track these kinds of things. The practical cost of the parent knowing something about the child, as you’re realizing, is trivial, worth it, and standard React (you look at the child API to find callbacks, why not consider the query a part of the “published API”).

tvaughan 2021-01-12T17:31:10.308800Z

Somewhat related, has anyone had any luck using https://github.com/tailwindlabs/headlessui/ with Fulcro?

henrik 2021-01-12T17:35:46.311600Z

@tvaughan Yeah, we use it in a project, and it works really well. A set of “blank slate” components is very refreshing compared to learning all wonky, bespoke styling APIs du jour used by most libraries.

tvaughan 2021-01-12T17:37:25.311800Z

Thanks @henrik. Good to know

tvaughan 2021-01-12T17:37:28.312Z

Yes, indeed. This has been my experience with Tailwind CSS/UI too

tvaughan 2021-01-12T17:37:53.312400Z

Thanks for packaging heroicons

2👍
henrik 2021-01-12T17:39:06.314100Z

I haven’t used the dropdown though, for that we use react-select (and it’s a headache to style of course). But the rest works well, including transition.

yubrshen 2021-01-12T18:07:02.317900Z

How to get started with Fulcro/RAD? I've just finished some tutorials of ClojureScript with Re-Frame, of Web page and server development with Clojure libraries (ring, hiccup, etc.) I'd like to use Fulcro to do a MVP of time management app (similar to ToDoMVC). I wonder what's your recommendations of my route of getting to the stage to understand https://github.com/fulcro-legacy/fulcro-todomvc and be able to port it to Fulcro 3, and can adapt to my own MVP? There are so much information available about Fulcro, which is great, I hope to get some advice to get up to speed as soon as possible. Here are a few option of paths: 1. Study https://book.fulcrologic.com/ up to Chapter 4 (Getting Started); 2. Watch https://www.youtube.com/playlist?list=PLVi9lDx-4C_T7jkihlQflyqGqU4xVtsfi (at least 18 segments, could be very time consuming); 3. Directly follow https://github.com/fulcrologic/fulcro-rad-demo and https://book.fulcrologic.com/RAD.html#_ui_validation I hope getting-started roadmap will help more future beginners. Really appreciate your help!

tvaughan 2021-01-12T18:32:14.325200Z

It's transition I'm most interested in. I have this (def ui-transition (react-interop/react-factory Transition)) and my own components that use Tailwind transitions, but I'm not sure how to combine the two. Do you have an example you could share?

hayley 2021-01-12T18:33:27.325800Z

You might check the recent responses I got, though my question was more general. Personally I think I’ll start with the traditional fulcro 3 online book and probably read the whole thing to develop a foundational understanding of what fulcro offers. It sounds like it’s harder to jump right into solving a specific problem with fulcro because of all of the new concepts it introduces. Though I’ll say that jumping right in to my thing is definitely how I’ve preferred to approach other learning in the past.

1➕1🙏
henrik 2021-01-12T18:39:30.326100Z

@tvaughan

2🔥
Jakub Holý 2021-01-12T19:01:05.326600Z

But you can trigger a mutation from UISM. Couldn't the mutation trigger the route change?

Jakub Holý 2021-01-12T19:09:01.327100Z

You can try to read some of the Book, then try to "do your thing" and when you get stuck come humbly back to the book and go on ping-pong like that.

1🙏
2021-01-12T19:11:46.327300Z

Hi @yubrshen and @slack1304 - welcome! I would recommend starting with Tony’s videos Parts 1 to 7 on YouTube as he covers many of the pitfalls of getting started. The book is excellent but it is very long and covers many areas that you don’t need to get a general understanding of Fulcro. I would also recommend starting with a template either fulcro-template (https://github.com/fulcrologic/fulcro-template) or the Fulcro-RAD-Demo (https://github.com/fulcrologic/fulcro-rad-demo). Fulcro RAD is set of helper libraries on top of the base Fulcro 3 - they are not “separate projects” so you can learn Fulcro and Fulcro RAD in parallel. I would also recommend working with a project that you know is working (i.e. fulcro-template or fulcro-RAD-demo because setup is non-trivial). Making small adjustments and seeing the working results was useful to bootstrap my understanding. Good luck!

2❤️1🙏
tvaughan 2021-01-12T19:19:15.327800Z

Thank you @henrik!

1👍
Jakub Holý 2021-01-12T19:43:36.329Z

I have created https://github.com/fulcro-community/guides as a home to community created guides and created a draft of https://github.com/fulcro-community/guides/blob/main/learning-fulcro.adoc - I really need help with this one!

6👏
Björn Ebbinghaus 2021-01-13T21:22:06.359Z

@yubrshen Pins are not personal. You pinned this message to the channel.

Jakub Holý 2021-01-12T20:59:05.331300Z

🙏 If you have any input on how to best learn Fulcro, please https://docs.google.com/document/d/1XMWwwnxtukZ0o3ev4GH2Kpa8MvX4z-r4kYKJMaMBw2A/edit?usp=sharing that I will feed back to ☝️

tony.kay 2021-01-12T21:24:08.331400Z

Right, so my recommendation is “if you’re doing a production app and you know Fulcro, you are better to use the RAD template”. But, if you’re a beginner trying to learn Fulcro use the videos first with the getting started chapter. Really understand the core bits of the library. Everything else in the ecosystem assumes you have that knowledge. You should not use RAD until you understand enough Fulcro to read the source of RAD and go “Oh, I see, that’s just using this and this from Fulcro to save me some typing”.

1🙏
tony.kay 2021-01-12T21:25:54.331600Z

Write the most trivial things to start. If you are not feeling like you really understand query/ident/initial-state/transact/render, then don’t make more complex things until you do. There are not a lot of core concepts, and while those concepts are new they are also simple, but everything will be confusing and seem complex and hard if you don’t actually understand those 5 things.

1🙏
tony.kay 2021-01-12T21:27:54.331900Z

80% of the book is me riffing with those 5 things to show you how everything falls out from there. Many nses (dynamic routing, UISM, etc.) just add implementations based on those core concepts that show you “and this is how you might do UI routing with those concepts” or “and this is how you might do a state machine system with these core concepts”.

tony.kay 2021-01-12T21:28:22.332100Z

RAD itself is “here’s how you can eliminate a ton of boilerplate using these same concepts”

2021-01-12T23:09:28.336600Z

I’m building a simple Todo app in Fulcro RAD that has Todos organized into Projects. I have a simple RAD report that lists all Projects. Projects can have many Todos (via a ref attribute). My report’s source-attribute is :projects/all-projects, a global resolver that returns all :project/ids. My report columns are “:project/label”, “:project/project-todos” and “:todo/label” (:todo/label is a “to-many” :ref from :project/project-todos to :todo/id). When I render the report, it displays the :project/label and :project/project-todos a vector of id’s (which makes sense). However, I would like to display the :todo/labels in the report. What’s the proper way to have the report render the individual :todo/labels themselves instead of the “idents in a list” that it displays by default? Link to the c.e.model.project.cljc: https://github.com/aeberts/fulcro-rad-demo/blob/develop/src/shared/com/example/model/project.cljc And a link to the c.e.ui.project.cljc: https://github.com/aeberts/fulcro-rad-demo/blob/develop/src/shared/com/example/ui/project.cljc

Jakub Holý 2021-01-13T08:17:54.354100Z

@alex-eberts might this example (linked) help? https://gist.github.com/holyjak/207ed33c9ee7e003b9a779fa47c32d91

1🙏
Jakub Holý 2021-01-13T10:52:55.354700Z

@tony.kay could you be so kind and elaborate on > Row query inclusions (alternate to prior, cannot be used together) with a custom column renderer. namely what do you mean by "a custom column renderer"? I know I can have a custom ro/column-formatters but that does not help me because I do not have a column for the child entites (todos) added via row-query-inclusion . Did you mean essentially replacing the default sui-report/render-table-row (https://github.com/fulcrologic/fulcro-rad-semantic-ui/blob/4e331c855ef681152a418ece636628adb7303e25/src/main/com/fulcrologic/rad/rendering/semantic_ui/report.cljc#L50) with a custom one, that both renders the report columns and the row-inclusion-provided todos?

tony.kay 2021-01-13T14:56:09.358Z

I mean you can do a bunch of different things. There are escape hatches everywhere. You can customize render of a column with column formatters, you can take over row query/ident/rendering with BodyItem, you can take over the entire rendering of the table by supplying a body, etc. The generated row component generates a query. Read the macro. See where row-query-inclusions is used? See where BodyItem overrides the generated one? It’s pretty straightforward in the code I think. The rendering plugin doesn’t have many constraints from RAD itself (other than a basic entry point). I wrote SUI renderers one way, but there is definitely room to do it others.

Jakub Holý 2021-01-13T16:19:18.358200Z

Thank you. I did have a look at the code. My understanding it: 1. I can add the data using row-query-inclusion but then I cannot use column-formatters to show them - because on which column would I do that? There is no column for the data, it was added via query inclusion. Unless I add a dummy attribute and take over its column with a custom column formatter that would render the data from the query inclusion there. 2. Or I can have specify a ro/BodyItem with the desirable query and e.g. a custom row rendering to display them. 3. (I'm sure there are other, though perhaps more involved, solutions, such as completely replacing the report layout) Is that correct?

Gleb Posobin 2021-01-12T23:10:49.336900Z

Because this is transact! with target/ready I think.

Gleb Posobin 2021-01-12T23:11:11.337100Z

I have found this message: https://clojurians-log.clojureverse.org/fulcro/2020-11-11/1605099087.138200

Gleb Posobin 2021-01-12T23:11:17.337400Z

Which I think is the same issue.

Gleb Posobin 2021-01-12T23:15:59.337600Z

I didn't explain myself correctly: transact! is ok, I am using it now, (transact! [(dr/target-ready [...])]) seems to be the problem if it is inside the route-deferred. I suppose this happens because both the route! mutation on the router and the target-ready mutations are processed in the same step of the transactions processing, and if target-ready happens to come before, the router hasn't changed into the "loading" state yet.