Fork me on GitHub

I got rid of the error but now I get a warning [ 3.037s] [fulcro.client.primitives] component contaico.ui.root/IntegrationRouter-Union’s ident ([:integration/by-id nil]) has a nil second element. This warning can be safely ignored if that is intended. , a nil instead of the actual value.


@pvillegas12 That's when the props going into your component are not complete, can even mean nil for the whole props - but obviously it is nil for whatever the id is, just as it says. If you can't actually see the problem by looking in Fulcro Inspect, and your application works perfectly, then this message can perhaps be ignored - because it is referring to a temporary situation that has since corrected itself.


this goog.math.Long is annoying getting converted, somewhere in the routing code it is getting converted to a number and dropping the last digit 😞


I managed to extend the bidi protocol to convert it into a string, but it’s being coerced somewhere else


With datomic, what is normally the course of action to deal with the :db/id?


Normally the :db/id from Datomic finds its way into your client state and there are no problems.


The problem right now is that 44143192831950917 is too large


(the datomic generated ids, so they are being coerced by goog)


@tony.kay transit it sending ~i46157498134036548 which is a 64 signed integer. However, the :fulcro.client.routing.routers/by-id value in the database is pointing to 46157498134036540. I suspect there is a bug with coercing this 64 signed integers somewhere in the defrouter


That is extensible as well if you keep reading…you can customize how it coerce’s bidi parameters


that is coerce-param in fulcro.client.routing

👀 4

Got it to work, thanks! Thank you for making that extension point 😉


which is a multimethod


@tony.kay how I would I extend it?


ah, nvm, :default is called in case it does not pattern match 🙂


How can I load data for a given route without using the started-callback function with fc/new-fulcro-client


@pvillegas12 What is the use-case ?


I want to load a list of models when I hit the /list route. Once I navigate to the details, I want to load the given model as well. If I hit the details of the model /list/id I want to only load the model


@claudiu it’s mainly a question of, when I enter a route using defrouter what is the canonical place where I can fire a load action and have a ui marker in place to wait for data from the server to come back?


Think the most common place for that is in the mutation for changing the route.


ah I see, at that point I can decide to load depending on the current state of the db


@claudiu This works when you call the route mutation from your UI, what do you do when the user is going directly to a specific URL?


One option would be to conditionally fire a load action in the r/route-to function itself depending on the handler supplied


Without that, it would not fire the load correctly as it won’t fire the mutation (which is normally fired when a user clicks on a button)


what do you mean by going directly to a specific url, the first time the user loads the app ?


or refreshing a details URL such as /model/id


I usually have ssr, so I get the route data from the server in the app-state. But think for initial entry point, it's the started-callback that has to fire the right df/load or mutation for the route.


Right, but started-callback is an app-level loading, I would not want to fire the load action for a model in a the /models URL


started-callback will fire only once when you enter the app. There you load the current user and app-level stuff like that, but you could also load the data for current route.


worth checking out the fulcro-template and how it has html5 & routing.


Yeah, I’ve looked at it @claudiu trying to get a feel of what architecturally is better.


Currently, it seems that I would have to write ensure-* mutations everywhere where I change routes when I use the html5 routing


Referencing the fulcro template, I would have to do '[(nav-to route-name) (ensure-model-loaded route-name)] everywhere where I want to change routes


I could perhaps wrap it too, but I would still need to handle the initial state as you mention


plenty of flexibility, not much in fulcro getting in the way. Currently I'm experimenting with load data for routes co-located on the page component. Got it working pretty nicely but still very drafty stuff code wise.

👍 4

What is the API to pass down data through props for defrouter? I want all components to receive a handle to the ui/loading-data root level attribute


think you have to add them to the component query :query [ [:ui/loading-data] '_]


I want to avoid the root-level query by “passing it down” through props


but I need to pass it through a defrouter definition


if you need it in a lot of components maybe :shared (haven't used it yet)


not sure it's for loading markers though 🙂


not sure you can pass it from defrouter, but there the top component that the router is rendering , you can add it to the query there and just pass it via computed to the children that need the info.


Unfortunately :shared only updates if you force a refresh of the root query (e.g. you'd have to query for :ui/loading-data on root, AND put it in follow-on reads...which would cause a root prop re-query for each refresh. The link query first suggested it probably best for that one, though I'd use load markers instead for localized loading rendering.


Note that loading-data AND load markers are for loads. Neither gives indications for mutations. For mutations, you generally use ptransact, set a flag of your own on start, and then have one of the mutations (after the network one) switch the flag back. Wilker has thrown some stuff in fulcro-incubator around extending the mutation system to deal with this common pattern.




It is entity-centric (e.g. it uses the ref prop of mutation env to figure out which entity to mess with in state for its extra ops)


@tony.kay Got ssr working on nodejs: transact! seems to work out of the box, but for df/load (xhrio seems to be browser only) I made a custom network and changed xhrio with axios. Right now it works because I added a dummy timeout. Any tips on what would be a elegant way to approach the "when data finished loading" ?


My first thought would be to delay the response, and add an watcher to the app-state. And just check on every event the markers in the app-db, once loads are completed just resolve the request. Not sure it's the most elegant solution though.


@claudiu core.async comes to mind


Remember that load, by default, serializes requests. That means that the post-mutation of the last one will run, well, last 🙂 So, you could put your logic in a post-mutation of the last load that triggers your "done" async chan might be a nice way to coordinate on that


Be great to see a blog post or something related to what you did.


@tony.kay I'm working on a small "toy project" for the clojure community. Hopefully it will be something usefull, but the main goal is to have a fulcro "production app" that I can open-source (ssr, nodejs, graphql, routing, , and a few crazy ideas). Still early draft stages as soon as I have something working and decent code will make the repo public.


For ssr & my router idea, would help if I had something like: "as soon as the network queue is empty call this function, then forget about it". Don't know if it can be in fulcro core.


Hm. I'll think on it. The real network queue is deep in the bowels. I'll think if there is a non-intrusive way to do that


I really think your best bet is a post-mutation on your last load


I don't see a clean way to encompass "queue empty" without significant changes


There could be many queues (one for each remote), so it would have to somehow know that all of the queues are empty, but they are async channels with depth, and there is no core async peek. I guess you could do a very short timeout on take, but then you'd end up busy-polling the queues.


What's wrong with the post-mutation idea?


Just triyng to think of ways it can be applied as a "black box". Juat run function x (that may or not have loads) then if no network activity is present do render. The post mutation works but think it can get a bit complicated for stuff like load-actiom, parallel loads, multiple netowrks & loads that also need a post-mutation.


Noticed that fulcro has two keys in the state for network activity. Trying to see if I can just add-watch on those keys and just flip thr switch when there empty.


@tony.kay seems to work well with adding a watch on the state and resolving the request when network markers are empty. One catch is that I have to look at two keys (in progress & pending) and also have a case where there emty but my value is nil. For the nil one think its because of the local load , the global marker ui/loading is still true. Any chance fulcro could have a marker like :fulcro/network-activity bool ? (Something like global ui load marker, but applied to all network events and that cannot be turned off)


So, the problem with a general network activity marker is parallel loads, I think. If I remember right, the parallel loads don't go through the queue, and Fulcro itself doesn't do any tracking on them (it closes over them with a lambda). It would be possible to add tracking, I guess, but it is a bit tricky. Perhaps I could add some kind of counter for "number of things in flight". It's a reasonable request. In fact, it is kind of a hole that you can't know that network activity (globally) is happening without tracking it yourself. I think the original intention of the global load marker was to be that, but since it doesn't track mutations, it isn't as useful.


@tony.kay have you come across the pattern of loading data for each route (using html5 routing) at the started-callback level but also as you navigate the UI?


(the more I work with fulcro the more I like it :P)


I am trying to make sure all features of Fulcro have both a mutation, and a mutation helper. The * suffix on functions generally means they are functions for working on state-map, which can be used inside of mutations. Thus, route-to* is the one you use inside of your own mutations.


When I use nav-to from my components, it triggers that function through the pushy/pushy setup below


yeah, that mess of stateful stuff is ugly 😞


but I want the nav-to to do a transact with two different mutations, one for moving the route and another to load data


I get into a circular dependency where I need the routing mechanism and the query from stateful components 🙂


(for the data loads)


muations are don't need to require them


though if you don't require them, then you have to type out the fully-qualified symbol


In order to load I need a defsc component to construct the query


(that’s what I meant)


What I mean is that you are probably requiring the mutations in the UI area so you don't have to qualify the mutation names


which creates the cycle


but it isn't necessary to require them


ah, got it, I can use the symbol referring to the ns I want


Several alternatives: 1. Use the technique described 2. Put an atom in the mutations ns (e.g. ComponentAtom) and reset! it after your defsc to hold the component (that keeps the requires in one direction, and gets you your aliasing) 3. Do what I said above, and don't require the mutation ns in the UI ns...go in reverse instead.


I’m requiring nav-to in my UI, a fn, not really a mutation per se


The technique of splitting your mutations into an "interface" and "implementation" in (3) might work also gets you the advantage of not having to quote your mutation expressions


then you can put your mutation implementation anywhere, independent of the declaration of it


Thus, you'll typically build a mutation to do your page transitions, which will use route-to* as a building block..then you can combine in db checks and load-actions.


It is safe to always add df/remote-load to the remote side of a mutation...if no load-action was submitted in action, it is a no-op

👍 4

I also sometimes use :componentDidMount as a place to put mutations that do things like "link in dropdown options" that are optionally loaded if missing.


E.g. I put the dropdown options in some top-level area (e.g. [::dropdown-options :states]) and the link mutation uses the ref of the env in the mutation to link some component prop (via ident) to the dropdown options at root. If the options are missing, then it issues a load with a target.


Would that hook be useful for data loading as well? (assuming you appropriately check for staleness)


You just need to understand when it gets triggered...a component can re-mount for various reasons, including a parent key change. So, as long as you're aware of that and cope with it, it's fine


I have a project based on the shadow-cljs template but I’m having trouble getting the browser cljs tests to work

(ns ^:dev/always ucv.client-test-main
  (:require [fulcro-spec.selectors :as sel]
            [fulcro-spec.suite :as suite]


(suite/def-test-suite client-tests {:ns-regex #"ucv.*-spec"}
  {:default   #{::sel/none :focused}
   :available #{:focused}})

results in
primitives.cljc:2362 Uncaught Error: Assert failed: (or (component? x) (reconciler? x))
    at Function.fulcro.client.primitives.transact_BANG_.cljs$core$IFn$_invoke$arity$2 (primitives.cljc:2362)
    at fulcro$client$primitives$transact_BANG_ (primitives.cljc:2362)
    at fulcro_spec$runner$novelty_BANG_ (runner.cljc:71)
    at fulcro_spec$runner$render_tests (runner.cljc:76)
    at reporter.cljc:228
    at cljs.core.MultiFn.G__57251__2 (core.cljs:10857)
    at cljs.core.MultiFn.G__57251 [as call] (core.cljs:10843)
    at client_test_main.cljs:7
    at cljs$test$run_block (test.cljs:448)
    at test_BANG___73248__auto___87232 (client_test_main.cljs:7)