Fork me on GitHub

One thing that occured to me when preparing a Meetup talk some time back was to differentiate between different kinds of keywords. The keys that are often named by-id are ident keywords and are different to query keywords. I don't think it helped my Meetup talk audience at all 🙁, but helped me.


Hi folks, I am currently reading the interactive tutorial for untangled. I just finished reading "untangled_tutorial.A_Introduction" and when I click on the link "Let's start with the UI" at the bottom it does take me to the correct page, but I am not starting on top of the page, but somewhere in the middle. The same is true for the links "UI exercises" or "next chapter" at the bottom of page "untangled_tutorial.B_UI". Should I create an issue on GitHub for this? Or is this already known?


@fatihict Thanks for reporting, it is already known. It looks like something funny that happens with devcards but we haven’t spent time trying to figure it out because it’s close enough 🙂. We might take a look this week, we’re doing a team sprint on improving the documentation.


Any questions about untangled so far?


@ethangracer Cool 🙂. I am going to read the tutorial first before asking silly questions to you guys. Also, I am a graduate intern sitting next to @mitchelkuijpers and it's really helpful that someone next to you is explaining this stuff 🙂. If you guys need a beginner to Clojure/ClojureScript to read documentation to verify if it is understandable, I am willing to do it 😄


Oh awesome! Mitchel mentioned yesterday that you might be helping us out. We would absolutely appreciate your feedback on any and all of the tutorial documentation / videos / etc. We want to make the Untangled introduction as clear as possible


Nice, so far I've watched quite a few of David Nolen's and Rich Hickey's talks and one of Tony Kay (I really liked that one by the way). If you guys have any material I will gladly have a look and give my feedback on them 😄


@ethangracer I’ll talk to the rest of the team, we’d love to write a testimonial. One thing I would be interested in hearing more about in the docs is how the Untangled team manages different views after a data load. For example, we’ve found a common case to be that one component might want all the items in a table while another just want’s a subset. It took us a bit to realize the benefits of making ident’s for the lists themselves, like :person-list/by-id, where the ident is :all for the list of all items, and maintaining that list in any data loads as post-mutations.


thanks @gardnervickers! that’s an interesting thought for a cookbook recipe, managing lists of items. Your approach is one that we haven’t taken — we do something similar where we query for [{:items [:id :name]}], where the sub-query is on a component that normalizes to :item/by-id. So once the data has loaded it looks like this:

{:items [[:item/by-id 1] [:item/by-id 2] [:item/by-id 3]]
 :item/by-id {1 {:id 1 :name “foo” }
               2 {:id 2 :name “bar”}
               3 {:id 3 :name “baz"}}
So that way we have the items by id automatically put into the :items list at the top level of the app state, which we can query for from any component with [:items _]. No need for the post mutation.


Your approach leaves a “cleaner” top level of the app state though


Ah ok we were thinking of doing that too, when you need a subset of the full list of items, do you filter after the component get’s the result of querying :items or build sub-list through a mutation?


@fatihict awesome, I’ll send some stuff your way toward the end of the week


@gardnervickers yeah we just use filter, it’s quick


Hmm that seems a lot less involved than our approach


is a post-mutation changing the react-key?


sorting into different lists would obviously be more time efficient for large data sets, we haven’t had to deal with that though


@w1ng not unless you explicitly ask it to


and it wouldn’t really be the best place to do so… you can add :untangled/force-root-render or something similar as a read to any query and it will force a root render


I’d have to look at the data fetch / mutation doc strings to remember exactly when it applies


@gardnervickers to your point though, it’s a fairly common requirement and we should absolutely have a cookbook recipe for that if we don't


or make it easier to find at the very least


Nice tip about :untangled/force-root-rerender - I think we've probably needed that and worked around it before. If I remember correctly, we read the "ui/current_route" param we have to trigger a rerender from root, since in our case the rest of the app is based on that.


yeah we were doing the same thing for awhile and decided it wasn’t the most declarative way to trigger a root rerender. it does work though


remember that you can trigger a root re-render by just doing a follow-on read of anything the Root queries


the react-key is about forcing React to re-evaluate the render even in the face of unchanged data


typically, you only need the latter during development, and it is rather heavy-handed otherwise


We do force root render in a couple of cases (which updates the react key, if memory serves), but those might change over time as things stabilize. I think we currently do some internal forcing around post-mutations to ensure that markers are updated, but iff post-mutations are used.


there’s a readme in there about managing lists, along with a more fleshed out example of what we were talking about earlier


What was unclear to me was specifically how to manage projections/views from different tables. The common case for us is that we have several components that all have a view over every element in a table, but some of our tables are way too big and we need to only show a subset. Analogous to you’re approach with querying lists of idents at the top of the db using links, we started making tables for our different list views like :person-list/by-id :all, :person-list/by-id :new-york :person-list/by-id :chicago etc… That way we can default to :person-list/by-id :all, and opt-in to building/maintaining sub-indices if things get too slow.


ahhh interesting


to my knowledge there isn't an accepted design pattern for that kind of problem yet, but it looks like what you’re proposing is a good one to me


A component (subtree) will re-render when:

- It is the initiator of a transaction
- A transaction mentions one of the things it queried in a follow-on read
- Has the same ident as a component initiating a transaction
I actually had no idea about the third bullet point, but that plays in our favor with this approach too!


@ethangracer @gardnervickers That kind of is the intended design pattern. In stock Om Next you write different parser routines the try to generate (and somehow memoize for speed) various views of the same data. In Untangled, we just use app state and pre-memoize them.


then query the versions explicitly


Idents normalize everything to prevent duplications


make the caching story a bit more directly apparent as well


Yup that’s becoming clear, it work’s well with things like the data-fetch/load-data where you can just pass :ident [:person-list/by-id :all


yeah, that too


Om has the elegant design, we just chose an implementation that seemed general purpose and logical


and easier to write/maintain than a parser


Yup, I struggled with writing my own read client parser quite a bit


Are there plans to support http caching?


for that to be usable, you basically need access to multiple remotes...which we also need to add hooks for


once you have that hook, everything else is up to your server code response and the browser


Ok great so it’ll be like vanilla Om.Next’s approach?


we're trying to be really thin


actually, I'd say we don't do anything differently than vanilla. We're just supplying reasonable implementations for the stuff that Om Next "leaves up to you".


parser, network plumbing, merging data, database format, i18n, support viewer of history, etc.


Om Next really does require you write a lot of code just to get started.


^^ that’s a great blurb for the main page of the site


We're realizing that this message needs to be more central in our description of Untangled


tony are you pancia? I forget


or is he on your team


oh it's adambros


@jasonjckn Anthony is a separate person 🙂


Is he on your team or independent?


just curious


on our team


i'm just eyeing his PR 😄


yeah, we're making a lot of PRs for doc improvements


its actually not finished, hes talking about the defui one


the devtools one


there are like 5 of us working on that...oh yeah, that...more ideas coming there


we had lunch yesterday to discuss ideas


yah it looks like it's going to be an epic addition


we found a way, I hope, to make a complete extension point mechanism for defui...going to be really cool if it works 🙂


remember to test Deref / factory function in advanced compilation


I had difficulty with it


but that was 2 months ago


haven't tested advanced mode since


leave a note on the PR or ill forget


data normalization works for ident joins right, anyone test this? {[:ident-kind :ident-id] [:my :query :keys]} I want to start making heavy usage of this


@tony.kay Great description, when I was first checking out Untangled I was under the assumption it forced you into using datomic and heavily influenced you’re design decisions. As we’ve been using it and going through the code base it’s clear it’s just a layer over the top.


@gardnervickers yep, I for example only use the untangle-client, my server implementation is totally apart, in node-js using sql 🙂


@jasonjckn yes, norm and merge work with ident joins


I did just find a bug 15 mins ago related to it, though...if "not found" on the server, the plumbing crashes on ident join merges (issue #39)


@gardnervickers Yeah, @ethangracer is working on the website as we speak and trying to clear up that misconception. I'll probably add something to the Om Tutorial of that sort about Untangled 😄


Neat, thank’s for all you’re hard work, this has been a pleasure to work with.