Just a general question, I am kind of running into problems with the way om.next handles getting remote data. I just read some code of untangled and that makes a lot more sense to me. Is it possible to use that stuff without completely using untangled?
I mean the way it sends a mutation to load a remote field
@mitchelkuijpers not sure that anybody has tried. just looking through the code it doesnβt appear that it has any strict expectations that an untangled application is being used. you would have to set up your networking to support the data fetch api, which given the amount of time we spent getting it right, I probably wouldnβt recommend just from an effort/benefit tradeoff perspective. Iβd definitely be curious to hear what others in the channel think
@mitchelkuijpers So, Untangled exists because Om next has some complexity to it that we believe has a reasonable general-purpose solution. In particular, the need to write a parser is a trade-off that Untangled believes is too costly from a general engineering perspective.
At the end of the day, what you have to do (in your parser or in your database) is transform the raw database objects into a shape that will work for your tree. In Untangled, we prefer those transforms happen on user-driven events in a direct data manipulation manner (easy to reason about, lower cost on rendering overhead, generally easier).
Loads in Om Next are always some sequence of: mutate something in app state to track that you are loading, return remote
from the parser, get/merge the data (typically over top of the place where you marked that you needed to load), etc. It's the same thing over and over, but you end up peppering that logic about in a parser.
Untangled wraps the need to do the above sequence in load-data
and load-field
. They do what you're going to have to do in Om Next...they just make it less work. They also deal with the potential problems of out-of-order completion, parallel queries for the same object (asking for different attributes), deep merge, and other issues that would normally show up in your program as bugs that would be mysterious to you.
So, I don't have much interest in supporting the use case of "what can I pick out of Untangled?" The answer is: nothing useful. The main advantage of untangled is reducing the central complexity of Om Next: removing the need for a parser and lots of networking/load logic.
There are trade-offs, and there are missing features that still need added, but we're having great success with it. The problems we've run into (and others using it commercially) have been easy to work with, or resulted in extensions to the framework.
Aha that makes sense, I'll try it out and maybe switch over then. Thank you for your detailed answer much appreciated! @tony.kay
Check out the getting started videos, for sure
and the tutorial, and docs, etc.
cookbook
I also gave a talk at an Unsession in Seattle that is up on YouTube that details some more rationale
https://www.youtube.com/watch?v=TU9hWTZcKy0&index=3&list=PLVi9lDx-4C_Qsgm8JC1VyMevV9DVj-dCh
I've been doing what I can to make it approachable. Lots of demands on my time, but I do understand that there is a hurdle to Om Next and Untangled. Trying to get people over the hump. This stuff really is so nice to work with. There are "easier" front-end things to get started with, but as soon as you try to do something "real" the easy goes away.
Untangled/Om Next keep the overall picture much simpler
β€οΈ
We just had our company hackday - I used untangled and I surprised myself by how amazingly fast and easy it was to work with now that I (mostly) get it.
Yeah I was coding something up last night from scratch and was just flying and giggling maniacally about my super-powers π
:man_in_business_suit_levitating:
I will try it @tony.kay I have had some big problems with the way remote reads work with vanilla om.next. But it mostly solves a lot of other problems. We are moving away from re-frame to om.next and maybe untangled π
@mitchelkuijpers At the very least: with Untangled you write Om Next code: you just avoid the overhead of writing a parser and a bunch of plumbing. Worst case is you abandon Untangled and write a parser...so you really have nothing to lose
it really is additive
Damn it.. Now I have to migrate some code
I guess you are right
And if you abandon it, well, then you "get to play" with process-roots
to fix your UI queries for your server, and implement your own remote loading scheme, etc. π
Is this still the case? IMPORTANT: NOT READY FOR USE. Clone TodoMVC from github as a template instead
or can I try the template?
you can try the template: FYI, I am working on the template TODAY
Yeah that is exactly what I am fighting with
especially the cb
that sometimes needs a query and sometimes does not need a query
just testing it now
Awsum I will test it with you then
I can send you a tarball of it in a few if you'd like
it will take more time to integrate my work with the lein template system
Cool I would like that
making it deployable to Heroku as well
I just want to test some stuff out
Aha wonβt use that but thatβs pretty cool
I love heroku
I am going to eat dinner and then I will play around with it, thank you so much for your time @tony.kay
still in the works
having trouble with server code refresh, but it mostly works. Feel free to check it out, and you can just pull as I work on it
@mitchelkuijpers ^^^
@tony.kay Nice thnx ^^
@tony.kay do I need to make a index-dev.html in the resources folder?
I have it working nvm
Very impressed so far.. This could have saved me a lot of time
yeah, it is nice to work with. Turns out my problem was with intellij. pushed a few minor patches to project file, but otherwise it should be pretty good
The InitialAppState idea is pretty damn nice
yeah...makes things SO fast to prototype
I threw together that whole UI so far in about an hour with server interactions
another bit of time for css
It seems like you pretty much only write mutates and run txes to get remote data am I correct in assuming that?
Cool website btw
ooops...seems like I lost the HTML files
do you have them?
I made one myself
π
that was an accident
I wiped em unintentionally π
No worries, only cost me 5 minutes. untangled will probably save me hours
html pushed
What is the main pattern to load data? just put it in the componentWillMount?
there are 4 files. One for specs, one for devcards, one for production, and one for dev
Aha cool i will pull them in
load data happens mainly in two places: 1. There is a start-callback in core.cljs
2. Due to user events
it is possible to put them in componentWillMount, but I have not needed to. Another option is you can write a mutation that uses the helper functions load-data-action
to emit a remote request from any arbitrary mutation.
See the cookbook for examples
So, imagine your app just loaded: use started-callback
to get initial server state. Then you nav to some page you want to lazy load data for. Make a nav mutation that checks app state for the data, and if it is missing issues a load-data-action
call from the :action of the mutation.
that gets you your "load on demand"
Yeah we currently use secretary, so that would fit very nice
which always want to look into app state to see if it is already there
yeah, with secretary, you just pass the app
to transact!
to trigger your nav mutation
Yeah
If you have not checked out the specs and devcards, be sure to try them
cards.html and test.html
I have to plug this into a existing re-frame codebase so I will probably do it like that
you have to be running all three figwheel builds (the -D options in the instructions)
Oh I have just started it on the repl
Works fine
great
spacemacs?
I actually use ohai-emacs from Bodill
π
cool. Glad to hear it works for u
you should be able to just call (start-figwheel)
and it will start up everything
or you can call it with a vector of build id strings eg: (start-figwheel [βdevβ])
I will probably put untangled in our boot.build. Would you ever be interested in a boot option for the template?
Yeah works like a charm @adambros
i wouldnt mind, just shoot a PR on untangled-template whenever you got it
ill be updating it once tony figures out what he wants with his version
Cool will put that on my todo list
yeah, boot is on the TODO list, but none of us use it (yet), and we don't have the horsepower to maintain it. So at present any Boot pointers will be included sort of as documentation YMMV
Sure I wouldnβt mind helping out
Iβll have todo it anyways
Am I correct in assuming that I could just use my own endpoint on which I have an om/parser running which returns transit?
um...sort of.
let me think...there was some caveat
Oh. The error handling mechanism establishes some standards...which are undocumented
but for the most part, yes
You'd probably want to dupe the unhappy path stuff, but it is a small amount of stuff
and it needs a bit more baking anyhow
No problem.. we are currently using catacumba but figuring out how to integrate will not be hard I think
I guess I have a nice weekend project
no, the server stuff is all convenience except for some of the error handling formats that Untangled expects at the network layer. Easy enough to emulate
Oh I see the code
That stuff is trivial to reuse
should be
Cool I donβt see any roadblocks, thank you so much for convincing me
yeah, for that matter, just hook our api handler into your stack
Yeah I already found that, I can simply install ring middleware in catacumba
welcome. I think a lot of ppl still see Untangled as a competing framework to Om Next...we're just trying to make it easier
Yeah, I also saw it that way
Not sure how to fix that messaging. Maybe make that more prominent on the home page
Iβll tell it to everyone π
@ethangracer Did you just patch post-sweep?
@mitchelkuijpers thanks! Word of mouth doesn't hurt π
I see the Jira, but no PR
@tony.kay are you talking about the story in jira? Iβm pretty positive we fixed it ages ago, I havenβt seen mutation symbols in app state for quite some time
oh...ok, I honestly hadn't checked π
I just saw the story close and didn't see a UC change
yeah I marked it as already fixed
not sure when but I think it happened during a data fetch refactor
just FYI, I fixed the related network bug where the app stops trying to do network ops when it gets a malformed response
just added an exception try/catch...whcih should have been there anyway.
huh
didnβt even realized that was a thing
thanks π
you remember seeing (in console) malformed response '<' or something like that?
ohh yes
yeah...if you got that, you were dead. Reload required
awesome. yeah that was a pain
on 0.5.6 SNAPSHOT on clojars
excellent
also meant to ask, given the om is going to beta soon, where are we with untangled going to βbetaβ?
it would be nice to have more docs but the code itself feels pretty solid
Largely a change to public facing messaging and docs, yeah
Feel free to bang out more docs π
I keep finding more stuff to do π
want to get the ref guide and tutorial beefed up for sure
We have a lot of cool stuff that isn't even documented
protocol support
yeah
extra routes
pre hook
etc
do we have protocol tests for todomvc?
don't think so
ok, I can write those up pretty quickly in the near future
and definitely want to add more to the ref guide as well
config env vars
untangled datomic migrations
list goes on
yeah...all of those
initial app state - that one was HUGE on impact to devs
I've documented that in cookbook at least
I have a problem where my server gives me 500 with a load-field and then the client keeps trying eternally
i try to run this: (f/load-field this :users :fallback 'users/server-down)
what does your server-down do?
and this is my query
(query [this]
[:id
[:current-user '_]
{:users (om/get-query User)}])
I added that because I thought that might solve the issue
and what triggers your load-field?
looping is caused by your code
componentDidMount
hmm
lol yeah that is my mistake
oh yeah, like I said, don't do that π
yeah you are right
you have to have an ident for load-field to work, and you have to implement the server bit correctly. 500 is all you too π
No that is because the query is invalid
I implemented the server bit
The generated server query will be a join on the ident { [:user 1] [...] }
Aha ok
which is why it needs an ident
load-field is really just a helper for load-data that derives the query for you
So I should not need it?
you don't "need" it...but it does make things easier
read the code...it is only a couple of lines
pull the query, focus it on the field, join it with the ident
then do what load-data does
Ah ok Iβll read it
Ah now I get it.. It is for loading extra data of certain entities with a id, so for example to get the posts of a user
zactly
lazy load stuff you didn't know you needed yet, related to something you already have
also puts a marker in place so you can easily show a spinner in that spot
in render
(marker in app database where the data will appear)
examples in cookbook
gotcha there is to remember to query for UI fetch-state
Yeah saw that
I'm trying to reset my app state on user log out and getting an Invariant Violation: malformed Ident.
error. I'm using the same state that I'm initializing the app with, so I'm kinda confused at what the difference would be resetting the state as opposed to initializing it. Would the difference have to do with me initializing with a data structure (which is denormalized) as opposed to an atom?
You guys are great rubber duckies. I'm thinking that I need to swap it with the normalized state, not the denormalized one I initialized it with. And I can probably use tree->db
to normalize my initial state.
Well, that was a good idea, but still got the same error π
@grzm interesting. Are you forcing a re-render from root?
could be Om is trying to render a sub-tree and there is no state for it
I'd unmount it and re-mount it
That could be. I'll give that a shot. Where would I put the code to unmount and remount the root?
make some top-level function. Make sure you're keeping the app in an atom
then just run umount/mount on the app
I've never tried it...you're in untested territory π
Cool. That makes sense.
Yay! I was pretty happy that I figured out how to reset history.
you will need to make the normalized db, and there you're right: db->tree
ah. those might be nice to have in the lib, now that you mention it
in fact, it totally makes sense what you're trying to do on logout
clean it up nicely and perhaps we can integrate it as part of the app interface
I think it should even be added to om proper, actually. It's independent of untangled.
good luck there π
But, yeah, will do π
default db format vs custom format. Not general enough for Om, and initial app state isn't available in a general sense liek it can be with Untangled
Oh, I meant just the reset history function.
oh, yeah, that one I agree
@tony.kay Is this what you had in mind for remounting?
(defn remount-app! []
(let [reconciler (:reconciler @app)]
(om.next/remove-root! reconciler (gdom/getElement app-mount-point))
(om.next/add-root! reconciler ui/Root (gdom/getElement app-mount-point))))
oh, no, sorry
there is a mount/unmount in Untangled
part of the application interface
actually, looking back at the interface:
https://github.com/untangled-web/untangled-client/blob/master/src/untangled/client/core.cljs#L65
I see mount. I don't see unmount
we have reset-state
you're right on the unmount...oversight I think
I tried that, too. That gave me the same invariant error.
If you do your remount (with a reset-state in the middle), that is what I was talking about
I'll pound on it some more
gotcha. (I think)
yeah, looking over the code to refresh my memory. What you're suggesting (with a reset-state using db->tree) will likely work fine.
Technically, it would work "better" to do this through a mutation, and just include a root query key as a follow-on read
you can do a swap! on state in a mutation, query the Root query and initial app state to make the normalized "new" state
As I'm thinking about it, that would be the better approach.
That makes sense.
And feels cleaner
Is there a general root query key or should I just add a key for something the root requires?
For the follow-on read