Fork me on GitHub
#om
<
2016-04-21
>
tmorten03:04:30

@iwankaramazow: nice work on this router. Just out of curiosity, how do you recommend handling remote fetches to server? I couldn't ever get it to work with a recursive parser...

iwankaramazow04:04:42

@tmorten: I mostly do something like:

(defmethod read :app
  [{:keys [parser query ast target] :as env} key _]
  (let [remote (parser env query target)]
    (if (and target (not-empty remote))
      {:remote (update-in ast [:query] (fn [query] remote))}
      {:value (parser env query)})))

iwankaramazow04:04:46

And then I work with :query-root true with on subqueries, don't forget to use process-roots in your send function

iwankaramazow04:04:02

Example when :app contains some :navbar/items

iwankaramazow04:04:10

(defmethod read :navbar/items
  [{:keys [query state ast]} key params]
  (let [st @state]
    (if (nil? (get-in st [:app key]))
      {:remote (assoc ast :query-root true) }
      {:value (om/db->tree query (get-in st [:app key]) st)})))

iwankaramazow05:04:28

(defn transit-post [url]
  (fn [{:keys [remote] :as env} cb]
    (let [{:keys [query rewrite]} (om/process-roots remote)]
      (.send XhrIo url
             (fn [e]
               (this-as this
                        (cb (rewrite (t/read (t/reader :json) (.getResponseText this))))))
             "POST" (t/write (t/writer :json) query)
             #js {"Content-Type" "application/transit+json"}))))

tmorten11:04:36

@iwankaramazow: makes sense. Thank you for the help!

hlolli12:04:15

When I do mapping/looping on dom elements in om (using Sablono), in what cases can this warning hunt me back: Warning: Each child in an array or iterator should have a unique "key" prop.

mattyulrich12:04:23

Sorry - I’m bringing a question to the #C06DT2YSY channel from the #C03S1L9DN channel - basically I’ve been playing with implementing an existing react app to om.next. In the existing app, when a user logs in, I dispatch an ajax request for supplemental information associated with the user (which is then loaded in the app state).

mattyulrich12:04:37

I think the way to do something similar in om.next is to follow the suggestions in the “Remote Synchonization Tutorial” ie. create a read function for that data that conditionally triggers a remote synchronization. Am I on the right track?

devth14:04:29

any docs/posts about how to resolve tempids from remote response?

cszentkiralyi15:04:30

@mattyulrich: sounds like the right approach: write a read function for your extra user data, return it from state if it exists or read from a remote & merge it into your state if it doesn't

tomc16:04:49

I'm currently trying to use the most recent release of om (alpha 32) but getting an error "No such namespace: cljsjs.react.dom". I added a dependency for [cljsjs/react-dom "15.0.1-1"], but still no luck. Any ideas what I'm doing wrong here?

tomc16:04:02

Ahh, nvm, it likely has to do with the fact that I'm trying to add om to a project that already uses reagent, which uses an old version of react + react-dom.

jebberjeb16:04:24

I'm using a javascript library which has a function which returns an HTMLImageElement. How can I include that object in an Om component?

devth16:04:56

tmorten: thanks.

iwankaramazow18:04:20

@mattyulrich: yes you're on the right track, you could also go with a mutation, but a read makes more sense in this scenario (I think)

mattyulrich18:04:23

@cszentkiralyi: I guess I’m missing something with the reconciler behavior. Let me see if I can lay out a meaningful and concise example...

mattyulrich18:04:57

Let's say this is a class registration system where users register for classes - my reconciler defines: :remotes [:class-search] :send get-remote-classes

mattyulrich18:04:14

I've tested the send function; it collects the correct data if I pass in a user. But I can't seem to figure out what the reconciler injects to this function.

iwankaramazow18:04:42

a map of remotes and a callback

mattyulrich18:04:49

My UI has elements that query for :classes and the reader looks like: '(defmethod read :classes [{:keys [state] :as env} key params] (let [user (read env :user params)] (merge {:value (get @state key [])} (when (and (not (find @state key)) (not (= :not-found (:value user)))) {:class-search ???}))))'

iwankaramazow18:04:50

the callback is basically merge!

mattyulrich18:04:14

I can break in my sender - but can't seem to put the right info in the '???' bit to get the reconciler to provide me with app-state or user or anything meaningful.

mattyulrich18:04:36

Right - that “map of remotes” - that’s the bit...

mattyulrich18:04:50

Where does it build that?

iwankaramazow18:04:13

when initializing the reconciler

iwankaramazow18:04:22

the default one is :remote

iwankaramazow18:04:52

but if you add others and return :other-remote or whatever remote you added in your parser

iwankaramazow18:04:03

send will receive them

mattyulrich18:04:52

hrm - so my problem is that I need to get the :user data from app-state in the send method. I thought it made sense to have the reconciler inject that; but it sounds like I’m misinterpreting the role of the reconciler here...

iwankaramazow18:04:48

every parser method receives the app-state under :state in the env

iwankaramazow18:04:15

you've got full control over what you return in parser methods

mattyulrich18:04:25

so - when I return that map from my "read :classes” method {:value … :class-search ???}, I can see the reconciler invokes the send method…. but that’s not a parser method, right? so the :state isn’t available there, right?

thosmos18:04:53

@mattyulrich: you can also update the AST in the local parse function before it's sent to the send function:

(defmethod mutate 'user/update-option
   [{:keys [state ast] :as env} _ params]
   :value {:keys [:user]}
   :action #( ... )
   :remote (-> ast
                (assoc-in [:params :uid] (get-in @state [:ui/auth :uid])))})

mattyulrich18:04:45

ahh… that makes sense

iwankaramazow18:04:24

Thats a mutation by the way

iwankaramazow18:04:44

(defmethod read :classes
 [{:keys [state] :as env} key params]
  (let [user (read env :user params)] ;;this is invalid syntax
    ;; should be (let [user (get @state user])
   (merge
     {:value (get @state key)} ;; removed extra []
     (when (and (not (find @state key)) ;;find? -> (get @state key)
                (not (= :not-found (:value user))))
       {:class-search true})))) ;; return true or an ast

iwankaramazow18:04:26

The reconciler has a parser which interprets queries, if those interpreted queries return either {:remote true} or {:remote ast}, it will forward those to the send function

7h3kk1d18:04:22

In the om-next remote synchronization tutorial the reconciler has :remotes [:remote :search] Is remote and search each a different remote?

7h3kk1d18:04:59

I don’t see :`remote` being used anywhere. I’m def missing something.

iwankaramazow18:04:26

It doesn't get used in the tutorial 😉

7h3kk1d18:04:41

Well that explains what I’m missing lol

iwankaramazow18:04:41

:remote could be removed

mattyulrich18:04:33

@iwankaramazow: Thanks for this! Unfortunately, I’m still not sure where to make the connection between the local app-state available in the read function and the data injected to the send function. Is it missing because :user isn’t a remote?

iwankaramazow18:04:44

if your read function returns a remote (either {:a-remote true} or {:a-remote ast}, the reconciler will forward it to the send function

iwankaramazow18:04:20

(defmethod read :user
  [{:keys [state]} key _]
  (let [st @state]
    (if (get st key)
      {:value (get st key)}
      {:remote true})))

iwankaramazow18:04:37

this read function will check if the key :user is in the app state

iwankaramazow18:04:49

if so it will return that, no remotes

iwankaramazow18:04:02

however if :user isn't in the app state

iwankaramazow18:04:25

{:remote true} will be returned, the reconciler will forward it to the send function

iwankaramazow18:04:25

and there you will receive something like [{:remote [:user]} cb]

iwankaramazow18:04:00

where cb is merge!

iwankaramazow18:04:56

{:remote [:user]} => :remote is the name of your remote and [:user] the query

mattyulrich18:04:43

ok… that makes sense and is what I see in the debugger.

mattyulrich18:04:55

Ok - just reviewed the tutorial again after your description; so is the :query data is available in the :send function of the tutorial because it is part of the component query that initializes the read function?

mattyulrich19:04:51

Sorry to keep pestering on this - in the tutorial the :send function extracts :query data:

(defn send-to-chan [c]
  (fn [{:keys [search]} cb]
    (when search
      (let [{[search] :children} (om/query->ast search)
            query (get-in search [:params :query])]
        (put! c [query cb])))))

mattyulrich19:04:56

I’m suspecting that the om/query->ast call is populating that :query data...

mattyulrich19:04:36

If so - does it get that data because :query is part of the component query function or because it’s part of the component params function ?

iwankaramazow19:04:17

The tutorial is a bit misleading, (om/query->ast search) is more of an 'advanced' scenario

iwankaramazow19:04:17

:query is here something that's part of the IQueryParams

iwankaramazow19:04:31

a better name would be :search-text or something

iwankaramazow19:04:58

as you say, it comes from the params of the component

mattyulrich19:04:25

Ok - so I don’t need to call om/query->ast to populate the params?

iwankaramazow19:04:54

that functions takes a query and returns an ast

iwankaramazow19:04:19

the abstract syntax tree is something you probably want to modify if you need to restructure queries or pull some parts out

mattyulrich19:04:54

So - if I put :user-id in the params of my component and come up with a way to om/set-query! on that component after the user logs in, I should be able to extract that in my send function?

iwankaramazow19:04:45

only if your parser returns a remote with that component's query

iwankaramazow19:04:33

As an exercise you should implement that

iwankaramazow19:04:24

I'm going to make an example with authentication tomorrow for Om-Router

mattyulrich19:04:50

Ok - I will play with this! Thank you so much for the help; while I still feel in the dark, I think I feel a path to understand this stuff.