Fork me on GitHub

Just pushed another 2.0.0-SNAPSHOT to clojars. - Should fix advanced compilation (untested) - Added proper set-query! that should function properly - Fixed UI refresh bugs that were known - Updated README for 2.0 (github 2.0 branch) - Updated a number of docstrings - Pulled over some missing functions from Om Next - Removed some of the debug logging - Fixed SSR (partially tested) - Updated to React 16 - Added apply to factory render. This fixes a React warning. Should not hurt anything, but not positive - Pulled in recent bug fixes from Om Next unreleased commits This SNAPSHOT should be pretty good in terms of working properly with existing apps. Other than the known issues listed in the README-2.0 I’d appreciate people trying it out and giving feedback. NOTE: New users should probably avoid it. None of the documentation has been updated/verified, and a few namespaces moved.


what would be a recommended use-case for set-query ?


@roklenarcic The only use case I ever plan to use at the moment is to join in components with code splitting


which is written for you in routing.cljc 😉


If you load some part of your application at runtime, there is no way for the already-loaded part to have known what the components and queries were going to be. So, when you load that code, some component in your tree will have to join in the new queries…thus, set-query!


Om Next unified dynamic queries on components with the remoting in concept, so set-query was always a potentially critical part of a “correct” app; however, in practice I did not find that model practical, because it required you to write a custom query engine on the client and server.


The idea was that you could do things like this (which you can): Have a query with parameters, like this:

(query [this] '[({:people (om/get-query Person)} {:start 10 :end 55})])
and use that information to modify not only what a component got from the local db, but what it asked for from the server. The problems that make this impractical are: 1. You had to write logic on the client that tried to figure out “do I have 10-55?“, if not, ask the server for them. If so, do they need refreshed? 2. The “remote” side of the QUERY PROCESSING on the client would have to be programmed to modify the query to get the missing ones…“I have 10-20, so I need to modify the outgoing query to 21-55" 3. You had to figure out how to keep track of what you’d asked the server for (some kind of load marker) so another parser call wouldn’t trigger an extra load. 4. The query + parameters were not saved in history in a usable state for history navigation to work (keyed by js objects). So, support viewer and other neat features based on time travel are impossible So, the whole mess of logic about local and remote ended up convoluted. This was the original motivation for Untangled (now Fulcro). The realization was that you’d like to reason about your remote interactions in a more explicit manner, with a query you can tune right then (without set-query! at all).


So, technically, Fulcro is stepping back from the “grand vision” of Om Next. Taking the parts that are practical and simple, and fixing/redesigning the ones that were not (or just didn’t work out, like history nav with dynamic queries).


BTW: If anyone is dying to use dynamic queries with load…that is coming soon. If you combine the read-local hook with dynamic queries and load: you end up being able to reliably use dynamic queries on the UI to modify how load behaves 🙂


In other words (coming soon):

(set-query! this ui-factory-a {:query [:new-prop]})
(load this :thing ui-factory-a) ; sends a query for `[{:thing [:new-prop]}]`
I don’t expect this to be commonly used in Fulcro, but it does give you the original design capabilities of Om Next “by choice”


which is written for you in routing.cljc... routing.cljc of what?




built-in code


So, I’m fixing up load markers at the moment to be placed in a table instead of in-situ. I’m tempted to make false the default (it is currently true). This would cause a behavioral change (using an explicit true gets the legacy behavior). The new behavior will be to use a keyword to give your load an ID, and then it’ll just be placed in a top-level table you can query. That also eliminates the mysterious use of :ui/fetch-state, and lets you put the query for the load marker in the parent UI element that is probably not participating in the load. The one down-side is that the new query to get the load marker might be a bit tougher to hide from the server, if in fact, you query for it in a component whose query is used for the server. I’ll finish coding up the examples. The main question is if requiring explicit load markers (`:marker id-or-true`) on load should be the default.


@tony.kay Will the updates also affect the :target behavior ? Keep thinking about the scenario when using post mutation to move or prepend so that I don't get flickering.


That is why I’m doing this. Target happens at the finish, so it is fine. The load marker is currently what’s causing the flickering, right?


e.g. if you do :marker false :target [:a :b] then things are fine, but you cannot show “loading”


so, the workaround is to target at a false location, then move it into place. Yes, this change will fix that


You’ll be able to query for the marker with an ident


and it won’t touch app state at all


and :ui/fetch-state goes away


so, query becomes something like [{:child-to-load (om/get-query Child)} [::df/marker-table :child-load-marker]]


and load: (load this :tmp/top Child {:target [:thing :child-to-load] :marker :child-load-marker})


Awesome 🙂 can't wait to try out all the new updates. Any chance for a "prepend" flag or would that be to much in load ?


Hm…that is a good question.


for general load, it really sounds fine.


the integrate-ident family in general


:append, :prepend, :replace


something like that for to-many


yep. That would eliminate a lot of repetitive post-mutation use-cases 🙂 no need to look in the mutations file to see what's going on.


agreed. I’m thinking maybe metadata on the target like this: (load ... {:target (df/prepend-to [:thing :children]) ...})


I’ll think about it some more…it might make sense to go ahead and support multiple targets. There might be several places in your state where you’d like to hook up the incoming data


Also keep thinking about the remotes . What is your opinion about using remotes for html5history & local storage ?


not sure what you mean by html5history


but I am the one that suggested it for local storage


the html5 history is browser controlled and event driven


Just to do a om transact to that remote, and that should handle the html5Push to change the location (I don't use pushy) just to keep the logic outside of mutations file.


oh, sure…


You’d still have to hook up to browser events for it, but yes, you could isolate that behavior to a remote. I’d tend to limit the number of remotes, and would instead have something like a :side-effect remote that understands various mutations, which are invoked by using a parser on the incoming mutation.


but it is kind of a cool level of abstraction, esp once history gets richer


cause then you can just see everything going on event-source style in history


the one down-side is reads from these remotes if the remote is stateful, cause then your app state ends up with data that is a cached old version of the stateful thing


For html5 history, you’d hook the event up to a callback that would issue a load to read the data into app state. That kind of thing.


will give it a try 🙂 When I show fulcro most people think immediately you get all that but the price is "constraints" (including me at first). But constantly surprised just how flexible everything is 🙂


@claudiu Yeah, that is the primary problem: until you see how it all works together, it’s just a bag of features that requires you to choose tools and languages you might not already know. I need to figure out how to do a more concise presentation of that somehow of how the small number of primitives leads to you not needing so much of the cruft.


Yep that's one aspect, think it's really hard to do. The thing I liked most in javascript/react land was the crazy amount of working apps that were available on github. I really learned a lot just by taking them apart and putting them back together, trying to get the same result but changing the approach/flow.


Can't open source the projects that I build for clients, and still to new to clojure & om-next to contribute to fulcro. But think this is a great opportunity for me and others like me to contribute. My next project will probably a fulcro 500px gallery, built for fun and added to github. Something like


@wilkerlucio Thank you for open-sourcing I browse it from time to time and look through trying to understand the approaches taken & how things fit together. 🙂


cool, I'm happy it is being useful to others 🙂