Fork me on GitHub
#om
<
2016-07-27
>
thomasdeutsch15:07:18

i have a question that is om/react interop related. I want to select all input characters but i do not know how i can translate the js code

this.refs['myinput'].select()
into clojurescript. I make use of the "ref String Attribute"
(dom/input #js {:ref "myinput"
                :onFocus (fn [_] -code-here- )})

niamu15:07:52

@thomasdeutsch: I’m pretty sure you can do that like so, but I haven’t tested this: (.select (om/get-node owner “myinput”))

thomasdeutsch15:07:28

i would expect this to work: (.. this -refs -minInput select) , but it does not work.

anmonteiro15:07:17

or you wanted just a simple translation of your snippet?

petterik15:07:45

what about (.select (om/react-ref this "myinput")) ?

anmonteiro15:07:47

(.select (om.dom/node this “myinput”)) should work, no?

thomasdeutsch15:07:25

yes, it does work... strange. Thank you @anmonteiro

anmonteiro15:07:27

depending whether the select function is the DOM node function or a component function, use mine or @petterik ’s suggestion, respectively

petterik15:07:38

Did not know about om.dom/node. Will replace some of my code with that fn 🙂

hlolli16:07:30

Ok so I just discovered that elements that update local component state in a for loop tend to rerender. Trying to do variable amount of text fields with input-validation. The text field keeps going out of focus or becoming empty. The same setup without a for loop, works fine.

hlolli16:07:24

Also happens with map, as soon as I add (update-state! this ....) for :on-change in text input field. The focus will randomly leave the text field (anytime the textfield is inside a sequence).

peeja16:07:58

Is it incorrect to list the same key twice in a component's query? Potentially as two joins with different subqueries?

peeja16:07:22

I notice it doesn't appear to throw any errors, but I'm not sure what it the behavior ought to be.

anmonteiro16:07:09

@peeja: what’s the use case?

anmonteiro16:07:27

I’m actually not sure if calling db->tree on such a query would be additive or just execute one of them

peeja16:07:10

No use case, but I'm picking out a join child from the ast, and I noticed that I could cause there to be more than one with the same :dispatch-key.

anmonteiro16:07:50

it doesn’t throw, though

peeja16:07:14

So: undefined behavior, avoid it, there's just no assertion in place?

anmonteiro16:07:15

I’m not sure how it should be played with. probably something to think about when spec has parity with clojure? 🙂

peeja16:07:30

Sounds good. Thanks!

hlolli16:07:18

yeeees! Fuck, dont make my mistake and have a random react-key generator inside a sequence. 🙂

peeja17:07:10

Let's say I want to show a person's name and the names of their friends. I query for [{[person/by-id 1] [:person/name {:person/friends [:person/name]}]}]. But all I have is a REST API for Person, which returns the person's name and the ids of their friends. Even when I translate those ids into idents, they're idents pointing at people which I have yet to fetch, so om/db->tree leaves their data out when I read the key.

peeja17:07:39

How do I get the whole thing to make a second pass and hit the remote for each friend?

anmonteiro17:07:43

@peeja: I’d say override :merge in the reconciler

peeja17:07:35

I'm not sure I follow. The app state looks correct, except that the data for each friend hasn't been fetched yet.

peeja17:07:57

So, I've got {:person/by-id {1 {:person/name "Joe" :person/friends [[person/by-id 2] [person/by-id 3]]}}}

anmonteiro17:07:37

(defn overridden-merge [reconciler state res query]
  ;; next is the next app state
  (let [{:keys [next] :as om-merge} (om/default-merge reconciler state res query)]
    (if (every-person-ident-is-mapped-to-a-person-in-the-db?)
      om-merge
      (go-fetch-those-missing-people)))

anmonteiro17:07:50

@peeja: something like that ^

peeja17:07:19

How does go-fetch-those-missing-people interact with send?

anmonteiro17:07:42

so that function would need to gather-sends and schedule-sends!

anmonteiro17:07:28

@peeja: the other alternative is to just inspect the result that you get in the send function

anmonteiro17:07:40

and only ever call the callback whenever you know you have all the data

peeja17:07:16

Oh, interesting. That might work…

peeja17:07:35

Although, that's a pretty big pain (in both cases) if this isn't about fetching more people

anmonteiro17:07:55

so a multimethod should get you covered

peeja17:07:07

Let's say I want to show this person's pets, for instance

anmonteiro17:07:27

@peeja: so a solution to your problem would be to dispatch on the remote in the send function

anmonteiro17:07:39

if you’re fetching people, use the :people-remote remote

anmonteiro17:07:53

if you’re fetching pets, use some other, could be the :remote default

anmonteiro17:07:59

then dispatch on that in your send function

peeja17:07:15

Yeah, that's what I'm doing, but now I'm in the :people-remote send and I need to fetch each pet

anmonteiro17:07:44

call send directly? 🙂

anmonteiro17:07:02

yeah, I understand it might not be the best option

peeja17:07:10

I mean, ideally I'd like to be able to rely on the parser logic to map me back to the correct remote

anmonteiro17:07:26

@peeja: so the merge option should work for that case

peeja17:07:46

Is there a good way to call the parser from there?

anmonteiro17:07:01

om.next/gather-sends will defer to the parser

peeja17:07:04

I guess I don't really understand what gather-sends does. Is it documented anywhere?

anmonteiro17:07:55

probably not

anmonteiro17:07:41

@peeja: so all it does is call the parser for the given remotes with the third argument set to that remote

anmonteiro17:07:05

and return a map with {:remote *remote-query*}

anmonteiro17:07:57

you’d probably need to do something like that

anmonteiro17:07:08

gather-sends, queue them and schedule

peeja17:07:05

I guess I'm surprised it takes this much going off road. I would have expected something like this to be a pretty normal use case. Am I doing something wrong?

anmonteiro17:07:48

OK there might be another way around this

anmonteiro17:07:00

I just don’t have the full picture so kinda hard to tell what you really want

anmonteiro17:07:15

but here’s another alternative:

anmonteiro17:07:43

override the merge function anyways, but queue the keys you need to obtain from the remote for re-reading

anmonteiro17:07:57

by keys I also mean idents

peeja17:07:16

I think ideally, any time there's an ident in my query result with no local value, I want to read it from the parser

peeja17:07:24

Yeah, that sounds right

anmonteiro17:07:34

but I’m not sure if that will perform the sends

peeja17:07:59

What actually causes the sends to kick off (normally)?

anmonteiro17:07:34

add-root!, transact!, set-query!

peeja17:07:43

Ah, I see

peeja17:07:08

I was imagining it was more on demand than that

peeja17:07:14

but that makes sense

peeja17:07:46

Part of what's bugging me is that db->tree silently drops the idents it can't dereference

peeja17:07:35

I'd really like to trigger the sends when the read tries to return the person and finds there are idents it can't dereference yet

peeja17:07:09

For instance, the server may respond with idents for things that my UI doesn't actually care about

peeja17:07:23

and I wouldn't want to fetch those from merge

anmonteiro17:07:56

@peeja: so you just need a different heuristic in your read function, it seems

anmonteiro17:07:06

for knowing when to return :remote or not

peeja17:07:29

Oh. Right.

peeja17:07:25

So, when I read :person/by-id and I get a person with pets which aren't present locally, I need to use the :pets remote from there.

peeja17:07:25

Which gets back to what I was saying before: if db->tree could tell me that it was missing records for certain idents, it would help a lot.

anmonteiro17:07:59

I think that just falls out of the scope of db->tree

peeja17:07:28

That's fair, I'd just like to find a way to make this work without re-implementing db->tree

peeja18:07:31

Oh, I had it in my head that db->tree replaced broken-link idents with nil, but it actually leaves them as they are. So maybe I can just find them after db->tree has had its way.

peeja18:07:28

No, actually, that's not right… 😕

peeja20:07:45

It occurs to me that just recursing in the parser instead of using db->tree at all would probably make it work correctly. The issue I'm having is that only the root key's read implementation gets a chance to invoke a remote. If you call the parser recursively, each level gets to add remote sends. Unless I'm missing something?

peeja20:07:37

But I've been warned off calling the parser recursively, so maybe I am missing something…

anmonteiro20:07:15

@peeja: you don’t get to add remote sends on each recursive call, only the top level counts as you’d expect from a recursive invocation

peeja20:07:33

Well, sure, but you can collect them on the way out, can't you?

peeja20:07:37

That just sounds more sensible to me than db->tree. Each ident type gets to define its remote fetching logic

peeja20:07:52

Otherwise you have to repeat that logic in every key

anmonteiro20:07:36

might be a good option for your use case as it allows more fine-grained control

peeja20:07:58

Isn't "my use case" anything with a RESTful API?

peeja20:07:43

That is, an API that doesn't give me a single, queried endpoint for the entire domain

anmonteiro20:07:29

probably, but to be fair I have yet to write an Om Next application that deals with a REST API

ag22:07:48

@anmonteiro: a few days ago you answered my question about css-transition-group. I didn’t have chance to play with it until today. Still can’t figure it out. Do you have a working snippet somewhere? Thanks

anmonteiro22:07:54

@ag: never used it, mind posting a failing case so I can try to fix it?

ag22:07:25

hmmm. I can’t say I’m failing - yet have to learn how to make it fail 🙂 Alright, let me play with it, maybe I’ll find how to make it work.

ag23:07:33

this for example doesn’t seem to work:

(defn css-transition-group
  "Create dom entrance and exit animations. Ensure that you have a unique :key
  property set on each component/dom-element that you pass as a body"
  [opts body]
  (let [group (.. js/React -addons -CSSTransitionGroup)]
    (js/React.createElement group (clj->js opts) (clj->js body))))

(def cpt
  (om/factory
    (ui
      Object
      (render [this]
        (css-transition-group {:transitionName     "bar"
                                   :transitionLeaveTimeout 2000
                                   :transitionEnterTimeout 2000}
          (dom/h1 #js {:key "one"} "One"))))))

(defcard css-grp
  (cpt nil))

anmonteiro23:07:19

@ag: that snippet renders for me

anmonteiro23:07:23

was that not the problem?

ag23:07:37

transitions doesn’t seem to be working

anmonteiro23:07:58

@ag: working for me

ag23:07:22

really? hmm.

anmonteiro23:07:26

did you add the CSS?

ag23:07:35

yeah I did

anmonteiro23:07:04

let me get a snippet together

ag23:07:23

thank you so much… really appreciate your help

anmonteiro23:07:45

(defn css-transition-group
  "Create dom entrance and exit animations. Ensure that you have a unique :key
  property set on each component/dom-element that you pass as a body"
  [opts body]
  (let [group (.. js/React -addons -CSSTransitionGroup)]
    (js/React.createElement group (clj->js opts) (clj->js body))))

(def st (atom ["ONE"]))

(defui cpt
  Object
  (render [this]
    (let [lst (om/props this)]
      (dom/div nil
        (css-transition-group {:transitionName     "bar"
                               :transitionLeaveTimeout 2000
                               :transitionEnterTimeout 2000
                               :transitionAppear true
                               :transitionAppearTimeout 2000}
          (map-indexed (fn [idx item]
                               (dom/h1 #js {:key (str idx)} item)) lst))
        (dom/button #js {:onClick #(swap! st conj (str "ITEM-" (rand-int 10)))})))))

(def reconciler (om/reconciler {:state st}))

(defcard css-grp
  (dom-node (fn [_ node]
              (om/add-root! reconciler cpt node))))
CSS:
.bar-appear {
  opacity: 0.01;
}

.bar-appear.bar-appear-active {
  opacity: 1;
  transition: opacity .5s ease-in;
}
.bar-enter {
  opacity: 0.01;
}

.bar-enter.bar-enter-active {
  opacity: 1;
  transition: opacity .5s ease-in;
}

ag23:07:16

Thanks!