# om

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

bones 00:03:31

@dnolen just out of interest why is Om.Next authored in both .cljs and .clj ?

davewo 00:08:12

@bones macros aren’t possible in cljs

davewo 00:08:35

defui is a macro

noonian 00:08:36

cljs macros are written in clj, and is useable from Clojure as well

bones 00:08:52

Ah! Thanks

bones 00:10:40

Oh right, because by the time the "defui" is in the browser it's now js - all these macros happen at author time (om/clojure newbie if you hadn't guessed)

steveb8n 00:13:39

@bones: also it’s used on the server side to provide a service endpoint for a client parser e.g

bones 00:30:41

Oh right, thanks again

jannis 02:18:49

Yay. Added creating cards, deleting cards via DND, toggling card assignees by clicking on them in the card dialog to the kanban demo. It's all too easy. :simple_smile:

drcode 02:37:41

Hi, I have a minimal example that generates an error that I don't understand:

drcode 02:38:40

This example has a parent and child component. If you press the button the parser complains about a missing read function

drcode 02:40:02

The problem is it wants a read function for a query tag that's deeply inside the absolute query, at which point it seems impossible for me to give a meaningful read function, since all context is missing

drcode 02:41:11

My impression was, read functions for the parser are by default only at the top level, unless you write a recursive parser. Therefore, this error seems to make no sense.

drcode 02:43:12

My questions: (1) Is this error expected behavior, or is this a bug in om next? (2) If it's not a bug, why is the parser parsing something ONLY when I call "set-state!"?

drcode 02:44:10

(The other possibility of course is that I'm still misunderstanding query functions and that is causing this error somehow indirectly)

drcode 02:47:00

(BTW: This is taken from a larger program that has a richer state structure and more meaningful read functions- I removed them from this minimal example, this is likely not the cause of the error)

thosmos 02:57:23

I have a simple modified datascript here: The Counter component has a query that returns an entity that is then wrapped in an atom, watched, and then handed to a reforms form that binds to the attributes of the entity. When the form updates the atom, the watch function does the om/transact!. Does this seem like a reasonable way to do this? It seems like this is a potential use case for a simple to wrap the 'path and transact function into something simpler that can be handed to the forms. Or would that be over-complicating it?

snickell 07:07:09

Are there any OM-like javascript clones you guys would suggest? I know, heresay, but alas not free to use clojurescript for this project

locks 07:09:49

React :stuck_out_tongue_winking_eye:

snickell 07:10:09

oh the irony :wink:

locks 07:10:24

I think there was a React+immutable.js+redux setup somewhere or something

locks 07:10:29

which you could say stick closer to Om

snickell 07:10:46

But in particular, I'm thinking well thought out cursor based central-atom style stores, as opposed to verbose flux style 'write a mutator for every change'

dvcrn 07:13:43

@snickell: guess you won't like it then that completely gets rid of cursors and implements mutators for everything :wink:

snickell 07:15:24

dvcrn: as long as its not a string matching abomination like flux........

dvcrn 07:15:41

what do you mean by 'string matching'?

snickell 07:17:05

dvcrn: What I've seen of the reconciler approach of seems a lot more DRY than the various flux libraries I've noticed

snickell 07:18:14

dvcrn: Just in terms of: "how many times does the name of this action get repeated" they seem rather verbose

dvcrn 09:58:22

hmm I'm still fighting with normalisation. I have the following :send code (stolen from davids om-next demo):
(defn transit-post [url] (fn [edn cb] (.send XhrIo url (fn [e] (this-as this (let [val (t/read (t/reader :json) (.getResponseText this))] (cb val)))) "POST" (t/write (t/writer :json) edn) #js {"Content-Type" "application/transit+json"})))

Person looks like this:
(defui Person static om/Ident (ident [this {:keys [name]}] [:person/by-name name]) static om/IQuery (query [this] '[:name]))

but the resulting app-state is always empty after normalisation. :normalize is set to true. archive link to my previous post:

dvcrn 09:59:03

could the issue be that (t/read (t/reader :json) (.getResponseText this)) returns a map with the keys being string? can that conflict with the normalisation?

dvcrn 10:20:24

seems like that was the problem. Changed my (python) server to return this instead (based on
test_data = { "~:app/people": [ {"~:name": "David", "~:age": 22}, {"~:name": "Fred", "~:age": 29}, {"~:name": "Paul", "~:age": 20}, {"~:name": "Jiyoon", "~:age": 22}, {"~:name": "Bob", "~:age": 23}, {"~:name": "Mark", "~:age": 28}, {"~:name": "Jiwon", "~:age": 24}, {"~:name": "Dude", "~:age": 28}, ], }

now the app-state looks like this:
{:app/people [[:person/by-name "David"] [:person/by-name "Fred"] [:person/by-name "Paul"] [:person/by-name "Jiyoon"] [:person/by-name "Bob"] [:person/by-name "Mark"] [:person/by-name "Jiwon"] [:person/by-name "Dude"]], :person/by-name {"David" {:name "David"}, "Fred" {:name "Fred"}, "Paul" {:name "Paul"}, "Jiyoon" {:name "Jiyoon"}, "Bob" {:name "Bob"}, "Mark" {:name "Mark"}, "Jiwon" {:name "Jiwon"}, "Dude" {:name "Dude"}}}

dvcrn 10:38:58

should I contribute a wiki page how to use om with a remote server or is that better as a blog post?

hmadelaine 12:35:05

@jannis Congratulation for your demo app ! Thank you for sharing

jannis 12:35:14

No probs

dot_treo 14:45:37

@dvcrn that's certainly a gotcha that more people will have a problem with, so I think a blog post should be useful until the documentation in the wiki has an om next FAQ / troubleshooting part

dnolen 14:47:22

@drcode: what is the error? You haven't included that anywhere

hmadelaine 15:01:51

Hi @dnolen: in order to better grasp the big picture of Om-Next , I am studying Relay and Falcor. Do you have specific suggestion or reading the docs of the official sites will do ? Thanks !

dnolen 15:23:21

Just the docs. Also GraphQL spec

hmadelaine 15:23:54

Ok thanks :simple_smile:

dnolen 15:25:23

Also talk videos are great way to get high level picture

hmadelaine 15:26:11

That's what I am watching right now

hmadelaine 15:42:54

@dnolen: I am watching lana Kuenzel JSConf 2015. Do you have plan to provide optimistic mutation mechanism in the future ?

dnolen 15:47:49

Already exists and way simpler

drcode 16:00:57

@dnolen: The error is "Uncaught Error: No method in multimethod 'example.core/read' for dispatch value: :bar"

drcode 16:02:19

So now I'm trying to understand why it is calling the parser against the inside :bar tag as opposed to the outside :foo tag (as it does during regular loading of the app)

drcode 16:04:19

(and whether calling the parser against the internal :bar tag is intentional behavior)

tord 16:41:50

Is there any reason why doesn't follow the naming scheme of other Om/Om Next protocols?

tord 16:42:53

I would have expected

dnolen 16:46:21

II looks annoying?

dnolen 16:47:51

@dvcrn: any reason you’re not using transit-python? or are you?

tord 16:47:58

Well, there is om.core/IInitState...

dnolen 16:48:10

that’s not

dnolen 16:48:24

starting fresh is always fun

tord 16:48:34

True enough. Very unimportant, of course, it just seemed weird to me.

dnolen 16:51:11

@drcode: looking at your issue, I don’t see anything obvious - trying your minimal example now

dnolen 17:18:16

@drcode looks like an Om bug, but also highlights something weird about your example.

dnolen 17:18:28

the child gets nil props

dnolen 17:18:57

obviously breaking the contract established by the query

drcode 17:20:15

Yes, that may have happened when I widdled down a minimal example- Is that issue triggering the bug or are the two unrelated?

dnolen 17:21:00

they are related

dnolen 17:21:14

but still there is an Om bug here and will have to think about it

dnolen 17:22:02

it doesn’t really have anything do with the parsing

dnolen 17:22:11

the error you saw is just a red herring to a deeper problem

drcode 17:23:45

Yeah, I know there's several different parts involved and I couldn't tease the intended behavior out of it- Thanks for the info, I will work around it with this new information!

dnolen 17:24:08

yeah part of the solution may just be disallowing nil props

dnolen 17:24:15

that’s really what triggers the bug

dnolen 17:24:53

it just doesn’t make sense to allow nils to flow around like this

drcode 17:40:00

@dnolen: FYI, when I try to correct the nil props I still seem to get the same error (Not expecting response on this comment, just an FYI for your troubleshooting)

dnolen 17:41:06

Basically sounds impossible

dnolen 17:41:27

Otherwise local state wouldn't work for anyone. But will check.

akiva 18:15:05

I’ve encountered a browser-specific issue. Going through the Queries with Unions tutorial and the code in Putting It All Together is having intermittent issues where it beachballs with Safari 9.0.1 in 10.11.1. Chrome doesn’t seem to have an issue. I’m trying to see if I can figure out how to replicate it reliably but it’s definitely happening.

akiva 18:19:03

Yeah. I just restarted Figwheel, reloaded the page in Safari, clicked any ‘Favorite!’ button, and it hangs for five seconds or so. After that, you can click freely except sometimes it’ll hang again.

akiva 18:20:37

Not likely an Om problem but I wanted to point it out.

dnolen 18:31:26

Doesn't seem Om related at all and haven't seen that.

akiva 18:37:01

Yeah, it seems very localized.

dnolen 19:35:23

@drcode: k I can repro I think I found your bug

dnolen 19:35:30

another case that uncovers multiple issues :simple_smile:

drcode 19:36:36

Awesome- At least I'm helping make the product better :simple_smile:

thosmos 19:37:15

@snickell: sounds like what you're looking for. It's a javascript project based on Om, immutable data, and cursors.

dnolen 19:37:42

@drcode also sorted out where to put an error so that you don’t run into these useless misleading errors

dnolen 19:37:51

will probably go this route over preventing nil explicitly

dnolen 19:44:08

just released 1.0.0-alpha12

dnolen 19:44:12

@drcode: ^

tony.kay 19:54:21

So, om-next can re-render leaf nodes (and can run a localized query if there is an Ident). I have an example where this leaf node wants to transact on the local state, but also has been passed callbacks. The local transact (on just the localized query state) causes the leaf to re-render (with an isolated query based on Ident), but now the callbacks are not available because the path from root wasn't the source of the re-render.

tony.kay 19:55:16

is this related to your example @drcode ?

drcode 19:56:39

Not seeing any different behavior on alpha12 I'm afraid, no different error message... both with the version with nil props and there version where I tried to fix by giving proper props.

drcode 20:05:29

@tony.kay: Yeah, I'm guessing my confusion is around how handles localized queries (even though I don't have an Ident) but I don't understand my confusion well enough at the moment to speculate more.

drcode 20:07:44

@tony.kay: Your example sounds like a great find though, exactly the kind of issue that will trip people up in the future

tony.kay 20:07:59

Well, David has said your example demonstrates a bug...but it was unclear to me what the bug is (passing nil as props?). What I ran into seems like a case where the approach needs some touching up, and might be related to the same thing.

tony.kay 20:09:31

Seems like for callbacks to be a "reasonable" approach, you need to render (at least) part of the path to that far as I can see, it seems you need to render the path to the child (from root) to ensure that callbacks make it through.

drcode 20:11:02

@tony.kay: I agree with what you say about "path to component"

tony.kay 20:12:11

I can, of course, "fix it" by including query keywords (to root) in my leaf component transact: (transact! '[(mutation) :parent-state-kw])

tony.kay 20:13:16

but the point is that specific mutation only modifies the "leaf" having to mention my parents breaks composition/isolation/local reasoning.

tord 20:15:19

@tony.kay: Your Om Next overview is very helpful. Thanks for writing it!

drcode 20:15:34

@tony.kay: agreed!

tony.kay 20:16:12

You're is needing some corrections based on these latest realizations (I thought queries always came from root, but they don't)...but it also seems there is a bug related to waiting for a resolution

tony.kay 20:18:01

The presence of Ident, in particular, makes it trivial to let Om re-render all of the components with the same Ident, and since Ident is supposed to be client-unique, it is trivial to supply a read that can find the state for the thing with Ident by running a new (isolated query). Unfortunately, this seems to break callbacks.

drcode 20:18:06

@tony.kay: Yeah the "queries not from root" thing is something I need to understand better

tony.kay 20:18:47

My docs are written (as I clearly state) with an incomplete picture of the inside of David's head :simple_smile:

tord 20:19:30

Yeah, the inside of David's head is far too big for a single picture.

drcode 20:22:22

I remember when I was first learning CSS, my productivity over time was like 0%, 0%, 0%, 0%, 5%, 20%, %100, %100, %100... so basically a sigmoid curve with a very steep inflection point. Same thing with "om classic"... After I got the hang of it it was easy to be very productive

drcode 20:23:06

Now I'm still stuck in the "0% productivity" well for Om Next, but I can see the inflection point in the distance, can't wait until I finally reach it :simple_smile:

tord 20:24:14

I'm also stuck close to 0% for Om Next, but fortunately there is no hurry, as I'm already pretty productive with Reagent. I'll stick to that until I reach the Om Next inflection point.

dnolen 20:32:24

@drcode: if you're not seeing a new error than you probably have something wrong with your build

drcode 20:32:42

thanks, will check on my build

dnolen 20:33:34

@drcode: make a new failing example for me to look at once you've verified that's not the issue.

dnolen 20:33:54

Note there may be a error reporting bug here. You cannot pass nil props.

thosmos 20:34:06

@tony.kay: you mentioned not wanting to add a parent key to your leaf's transact!, but I think you're referring to the query parent. As you said, the render tree needs to exist to that leaf for its callbacks to work. So I think I'm hearing you almost saying that there could be a way to traverse the up the render tree from the leaf in order to make the query tree work?

dnolen 20:37:27

@tony.kay: mentioning parent key is wrong. Means you must lift the transaction.

dnolen 20:41:35

Callbacks + Ident action at a distance is interesting issue

dnolen 20:42:06

Probably need to be a bit more careful here and merge

thosmos 20:42:07

@tony.kay: this highlights something I've been wondering about, but haven't done enough experimenting yet to answer for myself, so I'll wonder aloud for now: Could there be a way, by following the render tree path back from any leaf query to a parent query, to be able to assemble a root query automatically (without needing to explicitly describe child queries in the parent query)?

drcode 20:42:30

@dnolen: Sorry, was a build issue. Needed to force a clean js build. Everything now appears to be working 100% on my end with Alpha12

dnolen 20:42:48

@drcode: cool

dnolen 20:43:18

@thosmos: not going to do that

dnolen 20:43:26

Too many perf issues

thosmos 20:44:08

yeah, plus if there's no direct query dependency between parent and child, then for all intents and purposes they're not really parent/child in the query sense, only in the render sense

dnolen 20:44:28

Also path optimization is looming

drcode 20:46:50

@thosmos: The way the Om Next approach (potentially) decouples the query hierarchy from the dom rendering hierarchy is really interesting to me.

dnolen 20:47:11

And no @tony.kay your issue is not related to @drcode's at all

thosmos 20:47:53

@dnolen: path optimization?

dnolen 20:48:55

Once people want to do recursive queries re-running query is a disaster

dnolen 20:49:17

You need to be able to skip everything and re-render only the child

thosmos 20:49:37

ah right

dnolen 20:50:59

@tony.kay: fixing your bug is easy

dnolen 20:52:03

The problem everyone is having is "is this a bug or how ya supposed to work" :)

dnolen 20:52:10

Keep asking!

thosmos 20:56:27

and reverse traversing the render tree from leaf to root in that situation to re-run the root query with only the changed bits is ___? It seems like knowing (or being able to decipher) the render tree path from any component could be useful for the indexer to know how to run just the changed leaf's query all by itself and to know to only trigger a render on it. But again just I'm wondering aloud at this point as I haven't done the research yet.

dnolen 20:59:26

What you're suggesting can't be made to work in any simple way I've been able to see.

dnolen 20:59:42

The complication is computed local information

dnolen 21:00:38

So you cannot just run a components query without throwing that way ...

dnolen 21:01:31

But I may have got an idea just now ...

dnolen 21:01:57

This problem is related to the callbacks issue

thosmos 21:08:29

yes, it's related

tony.kay 21:24:47

@dnolen: (on bug fix): Great, so it does not require rendering the path from root, I take it. Merging non-query props?

dnolen 21:25:35

OK good time to listen in … a big-ish change

dnolen 21:25:46

affects multiple things

drcode 21:25:49

pricks ears

dnolen 21:26:23

so the fundamental problem is that everyone is trying to put computed properties along with props that go along with queries

dnolen 21:26:41

this includes things like callbacks, and edit states and whole host of other things

dnolen 21:26:49

currently we’re abusing props for this

dnolen 21:27:05

the problem is fundamentally that queries don’t know anything about this stuff

dnolen 21:27:32

and then you have to do a bunch of goofy stuff to get it back

dnolen 21:28:17

move reads up, duplicate logic (in the case of path optimization you’d have to reconstruct this information since you can’t get it from the parent) etc. etc.

dnolen 21:29:03

all these stem from the problem of complecting props

dnolen 21:30:03

all these issues issues go away if you decomplect the computed stuff from props

dnolen 21:30:33

but Clojure already solved this problem years ago

dnolen 21:30:36


dnolen 21:30:55

leave the data alone, put the information about the information somewhere else

dnolen 21:31:20

if you do this then making sure it carries over is simple same as in Clojure

dnolen 21:31:32

collection operations preserve metadata

dnolen 21:31:43

in Om Next state transitions can preserve metadata too

dnolen 21:32:05

dealing with metadata directly is annoying of course so we can just provide a simple helper

dnolen 21:32:23

(om/computed raw-props {:edit (fn [e] (om/transact! …)})

dnolen 21:32:56

now when you change something with Ident, the other components can rerun their queries and also just copy over computed

tony.kay 21:34:30


  1. Have you considered implications of closures over parent? (Not saying anything is wrong...just noting a potential place to analyze)
  2. Perhaps add that to the generated factory instead of requiring additional calls?
dnolen 21:35:14

I don’t know what 1) means

tony.kay 21:35:31

If the thing in metadata closed over something in parent, and you cache it in metadata

dnolen 21:35:55

om/computed doesn’t care about closing over anything

dnolen 21:35:59

and it doesn’t matter where you use it

dnolen 21:36:10

inline, factories, parse … etc. who cares

tony.kay 21:36:21

right, but that (fn [e] ...) might have

dnolen 21:36:30

you in fact will need to be able to use it anywhere

dnolen 21:36:39

let’s not derail on closures

dnolen 21:36:43

it’s not relevant to this

dnolen 21:37:40

if you’re copying something over the closure can’t possible matter since you got it from the parent

dnolen 21:37:46

the parent didn’t rerender so nothing is stale

dnolen 21:37:59

if the parent did re-render … nothing is stale

tony.kay 21:38:08

that was my initial impression...but the caching aspect just brought it to mind

dnolen 21:38:27

copying cannot matter in this case at all

dnolen 21:38:32

you can’t be stale

dnolen 21:38:58

if you actually needed something from a parent whatever you had is history anyway

tony.kay 21:39:33

yep, since it would have re-rendered (and re-called you) when it changed.

dnolen 21:39:41

that’s right

dnolen 21:39:55

this is only about a child re-rendering without parents knowledge

dnolen 21:39:57

it’s safe

tony.kay 21:40:48

I see no other (potential) holes

dnolen 21:41:47

it’s a huge simplification

thosmos 21:41:51

so it's like a component level persistent state store that only exists until the parent rerenders?

dnolen 21:41:58

a bunch of problems I would had to have sort through disappear

dnolen 21:42:16

thosmos: yep

dnolen 21:42:25

but it can move over between state transitions

dnolen 21:42:31

and it doesn't eff up queries or parsing

dnolen 21:42:48

like what we’re doing today

tony.kay 21:42:57

Love it

dnolen 21:43:35

the best part

dnolen 21:43:44

any code you have now isn’t effected :simple_smile:

dnolen 21:43:56

but it means you can gradually fix to eliminate the surprises later

dnolen 21:48:38

om/computed om/get-computed ?

dnolen 21:49:25

@dnolen uploaded a file: ex. 1

dnolen 21:49:50

@dnolen uploaded a file: ex. 2

dnolen 21:50:16

it means the query part of Om Next becomes very pure

tony.kay 21:50:40

yeah, I'm loving it more by the moment. Naming...two hard problems in CS

dnolen 21:51:59

it’s definitely a big break from React since React uses props for computed stuff

dnolen 21:52:12

but it’s just a mess when you’re trying to do this super functional thing that Om Next does

dnolen 21:53:41

the big tradeoff is that this stuff isn’t visible at the REPL, will need tooling to see this information

tony.kay 21:54:12

computed, dynamic, generated....reading thesaurus

tony.kay 21:55:15


dnolen 21:55:32

alternative put this stuff into a special key

dnolen 21:55:38 on props

dnolen 21:55:46

then visible and still get the benefits

tony.kay 21:55:59

I kinda like that for pragmatic reasons

thosmos 21:56:17

or offer both options

tony.kay 21:56:18

eh...but ppl might use select-keys

drcode 21:56:19

I'm liking that too, though I don't feel I understand the tradoffs very well yet

tony.kay 21:56:31

to pare down maps to the stuff the query asked for

dnolen 21:56:47

tony.kay: people shouldn’t be doing that though

dnolen 21:56:58

that just goes back to people mucking with props you got from query

tony.kay 21:57:01

not in the components

dnolen 21:57:06

if you do that, you deserve what’s coming :simple_smile:

tony.kay 21:57:11

just trying to poke holes :simple_smile:

dnolen 21:57:31

@thosmos: not going to offer options :simple_smile:

dnolen 21:57:38

we’re doing one thing or the other thing and we’re sticking with it

dnolen 21:57:50

I prefer key for visibility

thosmos 21:58:05

i like repl visibility over special tooling

tony.kay 21:58:10

orthogonal concerns leans me towards metadata, but visibility leans me towards keyword

drcode 21:58:12

Oh no, Om Next is becoming an "opinionated" framework :simple_smile:

tony.kay 21:58:31

the latter is a tooling issue

tony.kay 21:58:49

which we can write a bit of code to address

tony.kay 21:59:00

I can live with either one

dnolen 22:00:07

ok going to go w/ special key unless I hear something better in the next 5 minutes while I code this up :smile:

dnolen 22:01:28

oh hrm

drcode 22:01:31

I think the concept is sophisticated enough that people will be helped by just being able to (print (om/props this)) and see that there's some special stuff in there.

dnolen 22:01:32

so one issue

thosmos 22:01:39

what about a key on local state? would that make it more clear that it's transient?

monjohn 22:01:40

Visibility seems to me to be more important

dnolen 22:02:04

@thosmos: visibility problem

dnolen 22:02:07


dnolen 22:02:28

so it seems like we would need to use key or metadata depending on which one is appropriate

dnolen 22:02:51

I’m not so worried about the vectors case to be honest

dnolen 22:03:04

since that’s nearly always a collection

dnolen 22:03:13

which will apply computed to it’s children

tony.kay 22:05:09

Yeah, all of the cases I can think of are ok if you just propagate it through

tony.kay 22:05:37

oh wait....merge it through?

thheller 22:05:53

just wanna throw my suggestion from a few days ago into the mix

dnolen 22:06:03

you don’t need to merge

tony.kay 22:06:11

each child will be explicit

thheller 22:06:14

(a-component query-data {:ref "hi"} ...)

dnolen 22:06:16

just read it off old props and add it to the new props

thheller 22:06:29

just make query data an explicit param

dnolen 22:06:34

@thheller: no changing signatures

tony.kay 22:06:58

@thheller: You can always write your own helper function for that (I keep annoying David with the same kinds of suggestions :wink: )

dnolen 22:08:06

changing signatures is a disaster for would be templating providers

dnolen 22:08:38

keeping om.core/dom and components in sync is just a hard requirement

thheller 22:09:18

didn't require om.core require (om/build ...) for everything?

dnolen 22:09:30

@thheller: yeah totally busted

dnolen 22:09:37

not going back to that

dnolen 22:24:40


thosmos 22:33:57

@tord: re: your earlier question around naming of, there is :wink:

thosmos 22:38:28

@dnolen: is there any chance of wanting a (defrecord Ident) in the future and then needing to name it something different because of that?