Fork me on GitHub
#om
<
2016-11-02
>
whitecoop02:11:05

I'm having some trouble getting CodeMirror to work in a Om Next component. I've not used React except with Om, so I'm not sure that I'm doing things correctly. I've tried creating the CodeMirror editor inside of componentDidMount using (dom/node this) but I get a CodeMirror error in the console. (I'm using CodeMirror through cljsjs.) Does anyone know if this the right approach?

peeja14:11:19

@arohner If you explicitly pass nil as the props, it doesn't matter what the child's query is. Rather than do that, you should pass in the part of the parent's props which correspond to the part of the parent's query that's (om/get-query ChildComponent). If the child queries for an ident/link, that part of the parent's props (the part that you're about to pass in as the child's props) will have been read from the root of the app state.

peeja14:11:49

That is, [[:foo _]] and [{:bar [[:foo _]]}] both read the :foo key from the root of the app state, but one puts the value it finds at [:foo] in the props and the other puts it at [:bar :foo].

arohner14:11:28

right, I mostly get how it’s supposed to work. What I saw yesterday though looked like a bug / weird behavior. I was passing nil to a component. On first render, its props were nil. After transacting :foo, it rerendered with :foo, though I don’t understand why

peeja16:11:06

@arohner Oh, gotcha. At that point, the indexer knows that that component is rendering :foo, so when :foo needs to be re-read, it'll re-render that component with new data without rendering its parent. That's incremental rendering. It's not obvious (and possibly not officially documented yet), but it's a neat trick. https://anmonteiro.com/2016/09/om-next-internals-incremental-rendering/

arohner16:11:35

seems like that violates an invariant? If it didn’t render :foo the first time, why render it after a transact?

dnolen18:11:41

if you have a query you cannot pass nil

dnolen18:11:01

I haven’t followed all the details of what you are saying but the query is a contract

asolove18:11:08

Ok so about Om and specs.

asolove18:11:26

I love the idea of uniting specs and queries

asolove18:11:18

I guess I need to think further about the implications of that. I'm still more familiar with "Om previous" so that may cover more of the cases than I realize.

asolove18:11:21

I wanted to use specs to clarify all the cases a component has to handle, like: no data, some data, remote data plus local incomplete state with a validation failure, etc.

dnolen19:11:05

@asolove all of that sounds good except “remote data"

dnolen19:11:12

we never want to talk about that

asolove19:11:09

Can you tell me what the right nomenclature is for distinguishing "persistable, valid, complete" data versus in-process data, like maybe an address form where someone has typed in only the street number. That data inhabits the same component as a "real" address, but it isn't yet safe to persist it, pass it to functions that expect a valid address, etc.

dnolen19:11:37

@asolove the point is components don’t care

dnolen19:11:45

that’s someone else’s problem

dnolen19:11:13

in om.next this is hidden from the UI via parse

dnolen19:11:39

thus there’s no reason for these concerns to infect queries

asolove19:11:40

Hmm, scratching my head about this, which means I need to go back and read some more om next code.

asolove19:11:08

Thanks for challenging that, think it'll be profitable for me to understand what you're saying.

dnolen19:11:40

om.next is about delivering the illusion to your UI components that asynchrony is non-concern

dnolen19:11:43

persistence is a non-concern

dnolen19:11:56

all of this is handled by your parsing logic

asolove19:11:38

That part I understand, but I do still have in my head a distinction about local state that isn't ready to be shown to anything else in the system.

dnolen19:11:55

right, I’m just saying you can do whatever you want

dnolen19:11:04

it’s just not ever going to leak into your UI

dnolen19:11:19

there’s a whole other thing around tempids for this problem as well

dnolen19:11:00

so you can construct completely transient complex data and commit that at your leisure

dnolen19:11:22

and the backend can communicate id transition

asolove19:11:18

more reading for me

anmonteiro22:11:03

@currentoor interesting. try this:

(extend-type om.tempid/TempId
  bidi/PatternSegment
  (matches? [_ s]
    (instance? om.tempid/TempId s)))

(extend-protocol bidi/ParameterEncoding
  om.tempid/TempId
  (bidi.bidi/encode-parameter [tempid]
    (str (.-id tempid))))

(def routes ["/" {[[(om/tempid) :id] ""] :tempid}])

cljs.user> (def x (om/tempid))
#'cljs.user/x
cljs.user> (bidi/path-for routes :tempid :id x)
"/2ed7c229-9d31-4b2f-bf24-cf23f2d8c52e"

anmonteiro22:11:51

(I assume you're only using this for path-for, I don't think it makes sense for match-route. Right?)

anmonteiro22:11:40

My trick above is to use a bogus instance of om.tempid/tempid

currentoor22:11:49

@anmonteiro thanks! Why wouldn’t it make sense for match-route?

anmonteiro22:11:11

because you usually want to match a route against a string (the URL)

anmonteiro22:11:21

not against an instance of tempid?

currentoor22:11:49

I’ve got a function that I use, looks like this

(defn url->route
  "Converts a url to a route structure. Uuid strings are converted to om tempids."
  [url]
  (let [{params :route-params :as route} (bidi/match-route routes url)

        parsed-params (u/mmap (fn [[k v]]
                                (cond
                                  (re-matches id-regex v)   [k (long v)]
                                  (re-matches uuid-regex v) [k (om/tempid (uuid v))]
                                  :else                     [k v]))
                              params)]
    (assoc route :route-params parsed-params)))

anmonteiro22:11:15

you're using match-route on a string 🙂

anmonteiro22:11:39

it's never going to be a tempid thing is it?

currentoor22:11:34

not sure I follow, ideally I would not have to call (om/tepid (uuid v)) in the url->route function.

anmonteiro22:11:03

(bidi/match-route routes (om/tempid))

anmonteiro22:11:05

^ just doesn't make sense

anmonteiro22:11:59

so you need to coerce it to a tempid from the param string you get

anmonteiro22:11:25

but path-for can be made to work, as in my snippet

currentoor22:11:28

I’m saying (bidi/match-route routes ”/dashboards/eaf9396e-c840-4a70-aa68-36e7b8bc6177/edit”)

currentoor22:11:44

but it returns a map with a tempid rather than a string

anmonteiro22:11:54

@currentoor and what I'm saying is that you have no tempid in that string

anmonteiro22:11:15

so the param map that bidi returns is always going to have string values

anmonteiro22:11:44

even in the case of regexes: [[#"\d+" :id] ""]

anmonteiro22:11:50

you don't get maps with number values

anmonteiro22:11:52

they're strings

anmonteiro22:11:00

because it's what bidi matched from the input string

currentoor22:11:20

but then we would never be able to have numbers or uuids returned from match-route?

currentoor22:11:23

maybe that is the case?

anmonteiro22:11:24

can you produce an example that contradicts what I'm saying?

currentoor22:11:48

i might be mis-remembering, i’ll check

anmonteiro22:11:51

@currentoor happy to be proven wrong! let me know if you find something, I'm curious now

currentoor23:11:47

@anmonteiro this is what i meant

anmonteiro23:11:15

didn't know about this, I'll be using this very soon 🙂

currentoor23:11:59

yeah it’s nice, but i’m not fancy enough to figure out how to make it work with om/tempids

anmonteiro23:11:27

I'm heading to bed now, but I'm happy to help you figure this out tomorrow if you haven't already

currentoor23:11:51

yeah that would be freakin awesome!

anmonteiro23:11:19

let me know if you make any progress, I'll read it tomorrow 🙂

anmonteiro23:11:16

it does seem, though, that bidi is lacking in extensibility to user defined functions

anmonteiro23:11:34

or it's there but just not documented anywhere

currentoor23:11:45

i did see this

anmonteiro23:11:16

or maybe it's possible, even, to do what you want but there's just no docs on how to

currentoor23:11:30

yeah… fun to figure out though

currentoor23:11:37

i gotta go, i’ll try later