This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-02-26
Channels
- # aleph (2)
- # aws-lambda (18)
- # beginners (81)
- # boot (3)
- # cider (25)
- # cljs-dev (274)
- # cljsjs (10)
- # clojars (25)
- # clojure (65)
- # clojure-austin (1)
- # clojure-brasil (2)
- # clojure-dev (33)
- # clojure-dusseldorf (6)
- # clojure-gamedev (3)
- # clojure-italy (17)
- # clojure-poland (3)
- # clojure-russia (7)
- # clojure-spec (48)
- # clojure-uk (45)
- # clojured (1)
- # clojurescript (26)
- # core-logic (2)
- # data-science (4)
- # datascript (6)
- # datomic (58)
- # defnpodcast (2)
- # docker (1)
- # duct (14)
- # figwheel (2)
- # fulcro (130)
- # graphql (3)
- # leiningen (1)
- # liberator (15)
- # luminus (5)
- # nrepl (1)
- # numerical-computing (1)
- # off-topic (45)
- # onyx (15)
- # re-frame (9)
- # reagent (3)
- # ring (1)
- # shadow-cljs (91)
- # spacemacs (8)
- # sql (23)
- # unrepl (38)
- # videos (2)
- # vim (12)
@tony.kay I followed the new UI routing guide today; it was clear and easy to understand. Thanks! :thumbsup:
Do I understand correctly that in a defsc
, this should give me a reference to the dom node? :componentDidMount (fn [] (js/console.log (fulcro.client.dom/node this)))
Because all I’m seeing is undefined
@pithyless you can try (js/ReactDOM.findDOMNode this)
, I think that works
@wilkerlucio weird; ok, so both dom/node
and findDOMNode
work; but the problem was my root node was a material-ui-next
component I was mounting. When I switched to a plain dom/div
everything worked fine.
For reference, I’m using the components via:
(defn react-factory [cls]
(fn [props & children]
(apply react/createElement cls props children)))
a good recommendation is to use ref
to point to things
(my-element {:ref #(gobj/set this "element" %)})
Is :ref
a react ref?
so, dom
stuff you need to use #js {:ref ...}
and on factory things {:react-ref ...}
oh i see
this way you can be sure you are targeting the correct thing
Hi, I am trying to figure out routing.
I based my setup on the Routing Video and the corresponding code and the chapters in the book.
My goal is to have a route like
with a list of postal addresses that can be added to.
Showing them works fine, but adding one via an input field clears all data from the ui. The actual processing of the added address works fine, tempid, server and all.
In the example there are static pages which get routet to from the routing tree as [:home-page :single]
.
Then there are dynamic pages that get routet to as [:report/by-id :param/id]
.
The former shows up in the db root. The latter does not, since it uses the normalized entities.
When I put an input field at the top of the list on one of the static routes to add an item it works and the ui updates. In my case that is the person list.
When I put an input field at the top of a dynamic page adding an item adds it to the db, the server with the tempid and all, but the page looses its data. In my case that is the person page with the addresses.
On the person/20
page there should be some information on the person and some addresses.
Does this really call for two nested routers?
But when I try to do it with one router, how do I pass the :param/id
from the url to the router. When I put in the static keyword for the pages all routes work but the :param/id
is not passed. When I put in the :param/id
I do not get the router to work, except when nested as in the example.
How do I build a TopRouter that can pass :param/id
to one of the otherwise static pages?
@magra Not exactly sure I understand everything. But have you tried just adding the url params where you need them by mutation ?
(def routing-tree
(r/routing-tree
--- more top-router routes. ---
((r/make-route :person-page [(r/router-instruction :top-router [:person-page :top])
(r/router-instruction :person-router [:person/by-id :param/id])])))
In the person router I can use the :param/id
. If I try to use only one router, where would that go in the :top-router
?I worked from this demo file https://github.com/awkay/fulcro-routing-video/blob/master/src/main/routing/html5_routing.cljs
@U3LP7DWPR are you suggesting to put them someplace else?
@pithyless how do you like material-ui-next - are you pulling in via shadow-cljs or cljsjs? I believe https://github.com/madvas/cljs-react-material-ui has an issue to pull in material-ui-next.
@donmullen so far so good, but I have not yet tried to do something crazy where my customizations will break everything. ;] I am running the latest 1.0.0-beta.34
via shadow-cljs
(which has been a joy to work with) and have integrated several react-virtualized
based components without a problem. The only issues I’ve seen so far are breaking changes (read the changelog before bumping versions) and partially integrated ThemeProvider
(so you have to sometimes set custom styles for components, where you would think it should just pick them up).
ident could be the problem if your router's ident function isn't consistent with the component idents
Refresh of a component works as follows: The component you transact on is queued for refresh. It's ident is used to create a query for JUST that component [{[ident of component] [query of component]}]
, and then Fulcro refreshes just that component (subtree). If the ident is wrong, then this query returns empty data, which will cause the component to clear
@magra The defsc
macro is build to help warn you of that, but you "fixed the warning" by adding :id
to the query instead of fixing the ident 😜
on reflection I realized I did give you a warning for that case: if your query doesn't ask for something in the ident...but if you fix it by asking for the "wrong thing", then it doesn't help 🙂
seems to me when you messed up the ident it told you :id
wasn't in your query, but was used in the ident...I'm guessing your "fix" was to add it to the query
@tony.kay on that, when I was trying to write a union component using defsc
, the error message about the query was confusing, it just said something like unexpected []
, I had to spend a good time to figure I had to make my :query
a fn
to use union queries there
@tony.kay I have the id plus :db/id in the query because I am still not to clear where the :param/id that bidi passes into the routing tree becomes the :db/id in the component called by the router.
So, :param/id
is just a placeholder that is replaced by the routing instructions based on the values in the routing-parameters map. Nothing at all to do with query or component
I have and thank you for the work you put not only into the libraries but also into the documentation. I will have to work through that a few more times 😉
When I pass data to a defcard-fulcro
does it need to be denormalized or will it automatically denormalized?
As the initial state, yes.
normalized. Devcards puts that in an atom, and when Fulcro gets an atom it wants it normalized…why not using initialstate of the Root , though?
I wanted to test the root component with different states. Maybe I’m doint something stupid
If you want to test with different state for UI verification, use a static normal defcard
https://github.com/fulcrologic/fulcro/blob/develop/src/tutorial/fulcro_tutorial/B_UI.cljs#L83
Initial state is really something that is a starting point…the started callback is where you would typically respond to the environment and modify how the app behaves once started
When I use a static defcard, I cannot use mutations, right?
…and feel
But I think I get it, for static, a simple defcard is the easiest
Yes, in the real world the come from the app state / queries. I wonder what is the advantage of defcard-fulcro
over having the application running then
Maybe a more concrete example would help? For a “person list” I want a defcard for the empty list, so I can see, and test the behaviour of adding a new person. I want also a defcard for a “person list” that is already populated with data. It’s well possible I’m doing something unusual or silly.
When I have a bigger application that has many of these components, person list, a organization list and other components, I thought it might be usefull to be able to test each component in isolation but including the mutations.
have an initial state that is the “true” initial state. Then in each card run transations and state merges that move you to the desired state
Things are relocatable, so you could even write “alternate” roots for the cards that embed portions of your app
that Root could have it’s own initial state that makes sense for that particular card
(by relocatable, I mean that idents enable your mutations to not care where in the UI things are at)
I’ve seen all the videos, which are great! It’s hard, though, to remember everything at once as fulcro offers so many features 🙂
(I’m thinking about doing a series of videos for liberator now, so you inspired me)
So, in the decard-fulcro expression I can use mutations and only the last expression must return a component?
Here’s a useful trick for cards:
(defsc CardRoot [this props]
{:query [{:test-users User} ...]
:initial-state (fn [p] {:test-users [...users...]})}
...)
placing something in the root that isn’t really used by the root can still get you normalization
you still need to link them into the UI, so perhaps it is just better to use :started-callback
with merge-component!
That’s the last map of the defcard-fulcro call then?
(defcard-fulcro xxx root/Root {} {:started-callback ...})
Oh, if CIDER had shown me the docstring I would have known
https://github.com/fulcrologic/fulcro/blob/develop/src/book/book/queries/union_example_2.cljs#L128
Let me try that, and thanks for the help.
With Fulcro version changed to [fulcrologic/fulcro "2.2.1"] in Fulcro Sample Application -- https://github.com/fulcrologic/fulcro-template *SSR* reports Cannot route: Unknown Screen
in rendered HTML output for main page (normally redirects to login page). Only with Server Side Rendering; client side works and overrides when ClojureScript loaded.
Maybe the sample application is just out of date? Report issue on the sample application?
if something breaks and all you did was a version bump, then I consider that a Fulcro regression
Did a git pull on the sample application and version bump. Not sure if I did a lein clean though; will try first.
Will report issue.
That's fast! Thanks, will try snapshot first thing tomorrow morning.
It’s worrisome. The “fix” should have had no effect. So, I’m still puzzled. And I don’t like unsolved puzzles.
Found it. The API wasn’t clear for getting the ident, and I was actually mis-using it.
Couldn't sleep without having tried fix. 🙂 Confirmed fix in 2.2.2-SNAPSHOT. It now indeed works fine!
@maridonkers still have to figure out why that change caused a problem…it hsould have been ok 🙂
@tony.kay One thing I’m unclear on in the “wire from leaf to root” is what happens at the Route level. In moving some code from devcard over to main/ui and putting the component within router controlled page - I have somehow wired up the components so that I’m getting a Assert failed: get-ident invoked on component with nil props
— within a component that has initial-state set and shown in the inspect-data graph. Assert happens in the call (prim/transact! this
[(load-grid {:pgrid-id id :grid-id grid})])` Code currently uses the bootstrap routing example. My Root queries the MainRouter -- should the Root also query and potentially get-initial-state for each of the screens referenced by the MainRouter? Currently my naive first-cut was for Root to reference a container component which is within one of the router-controlled screens.
Hey Don. Chances are you’ve pointed an ident somewhere in your state at an entry that doesn’t exist….thus you’re getting empty props on UI refresh, and that leads to this message.
Root should compose in the state of the main router. The router composes in state for all subscreens it controls (not Root…it is a tree). ALl of those screens must have initial state as well
Also, your ident functions must be consistent. This could also happen (as it did this morning for @magra) if your ident function returns the wrong thing.
I’m trying to think of something that can help with this issue more. It’s usually data consistency, but to be honest I got bit by it one or two days ago as well. It’s a nuance that is easy to screw up, and is so small it is hard to see.
So, a more explicit answer to your specific initial “unclear”:
The generated component from defrouter
:
- Compose the queries for all subscreens
- Compose the initial state for all subscreens
- Uses your supplied ident at the union ident function, which must match (in functionality) all of the screens under control
Here is the union component output function from routing: https://github.com/fulcrologic/fulcro/blob/develop/src/main/fulcro/client/routing.cljc#L34
Thanks @tony.kay. Breaking for dinner (on EST time) - and I’ll take a closer look. I forgot to mention - I am getting the warning PropertyContainer's ident ([:prop-container/by-id nil]) has a nil second element.
on PropertyContainer and two other components, so somewhere there is an ident that is off!