This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-03-17
Channels
- # announcements (7)
- # babashka (56)
- # beginners (114)
- # bristol-clojurians (4)
- # calva (22)
- # cider (7)
- # clara (1)
- # clj-kondo (17)
- # cljs-dev (1)
- # clojure (93)
- # clojure-europe (8)
- # clojure-italy (5)
- # clojure-nl (2)
- # clojure-uk (79)
- # clojuredesign-podcast (18)
- # clojurescript (108)
- # code-reviews (6)
- # cursive (3)
- # data-science (16)
- # datomic (151)
- # duct (7)
- # emacs (10)
- # events (1)
- # fulcro (76)
- # luminus (8)
- # off-topic (3)
- # other-lisps (2)
- # pathom (8)
- # re-frame (5)
- # reitit (8)
- # schema (9)
- # shadow-cljs (37)
- # specter (3)
- # sql (17)
- # tree-sitter (2)
- # yada (9)
@tvaughan The result action for loads is what does the merge and targeting. My guess is that your target is targeting through a to-many, and you’re therefore using a keyword as a key into a vector
Thanks for the reply @U0CKQ19AQ. There is a to-many relationship to a list of team names which does work. The selected team is one-to-one. I definitely do doubt that my query is correct. I have team-list/selected-team in the query so that it'll compile but I'm really not sure what the correct shape should be as this is never meant to actually be sent over the wire. It's just a reference in the client database. It definitely seems odd that selected-team disappears from the client database (as seen in Fulcro Inspect) after the list of team names is fetched
So, looking more closely at your TeamList code. Your query needs to explicitly join the selected team to the UI of the selected team:
[{:team/selected-team (get-query Team)}]
You’re referencing a normalized entity (by name, I assume, from your load).
I’m also confused why in one place you’d refer to it as :list/by-attr
and in another as :temp/name
. Don’t resolve the same data using different things: An entity/row/document in your real database should have a real ID, and THAT is what you should normalize by, otherwise you’re going to confuse the heck out of yourself.
One of the main points of Fulcro is to normalize your data model so things stay sane. If you suddenly normnalize based on a bunch of different names/keys/ids for the same thing, you’ve just propagated the same error that nearly every other UI library on the planet seems to want you to make.
> [{:team/selected-team (get-query Team)}]
I had this originally. I just tried it again and same error.
> I’m also confused why in one place you’d refer to it as :list/by-attr
We're using Datomic on the backend. :list/by-attr
is just a query that will return all entities with a certain attribute.
1. https://gist.github.com/carrete/6e77d0da5e12a6b0e6d600ac7972fb1a#file-components-cljs-L65
an ident is already a location in a database…you’re loading one thing and then rewriting an IDENT into a table instead of a map. Targeting should target either: a top-level key, or an attribute in a table entry.
but loading by ident, and then targeting to where a table entry should be will wreak all sorts of havoc
The UI reified graph needs to follow the very simple model described in the book: {TABLE {ID {map of attributes}}}
the only place edges are legal is at the root level of the entire db (since it can hold db table and edges), and as attribute values.
I should add an error check for that case for beginners. I can see how you could make the mistake or misunderstand it.
> See book/videos on properly loading/working with lists. I did. I thought I did this correctly 😞
Just to be clear, the list of team names does render correctly. It's the onClick elsewhere that chokes
The error you’re getting is because the target you specified is trying, after the component did mount, to target what should be an attribute in the proper model, but what it finds instead of a vector instead of a map.
welcome. What you want is to give the data that you’re loading a proper normalization story. Invent a resolver for the server for a top-level key (i.e. :all-teams
). (load! :all-teams Team {:target [:list/id some-list-id :list/all-teams]})
it should be something more like:
(load! this :team-names {:target (conj (get-ident this) :by-attr/resp)})
where :team-names
is just some global resolver that can give you the answer you want
use :params
to send parameters if you need them. Loading by ident is for loading an entity in it’s entirety, and would never have an ident target
use a namespaced keyword for that that describes the domain (i.e. :team/id
). It will save you lots of headaches later.
you want all info for the team entity going in the same spot, and you’d like to be able to debug it that way as well. As your app state gets complex, having one giant table of heterogenous entities will be info overload
I guess I was thinking I would like to avoid having team/id, team-name/id, selected-team/id, etc when really they're all just db/id
:team-list/selected-team
is an attribute that, in the UI model, should end up pointing to a [:team/id id]
and that Row is just one possible view…so, yes, looking over your code in general it does seem like you’ve generally got it, other than you’re using :db/id
for every kind of thing, which then makes pathom resolvers hard to write correctly
everything has an input of :db/id
…so your autocomplete in the query tab will say everything is accessible from :db/id
and you’ll have no reasonable chance at a security model based on names, because your ids are all collapsed into one concept (name)
True. Originally I loaded everything in TeamList, but I want to be able to load the most recent team data from the backend each time a team name is selected which led me to where I am now
(defsc TeamList [this {:team-list/keys [teams]}]
{:ident (fn [] [:team-list :singleton])
:query [:ui/selected-team {:team-list/teams (get-query TeamName)}]
:componentDidMount (fn [this]
(load! this :all-teams TeamName {:target (conj (get-ident this) :team-list/teams})}
(map ui-team-name teams))
> because your ids are all collapsed into one concept (name) In this example names have a unique constraint
no, I’m saying that your person entities are in the same fulcro db table as your team entities
> ;; you'd probably use computed state to pass in a selectTeam
callback, and at this layer you'd make that be a fn that does a m/set-value!
of :ui/selected-team.
Yeah, that's what I couldn't figure out how to do
Thanks again for your help @U0CKQ19AQ. If you're curious, this https://gist.github.com/carrete/6e77d0da5e12a6b0e6d600ac7972fb1a is what I came up with