Fork me on GitHub
#untangled
<
2017-06-07
>
adamvh03:06:18

ok, so what (df/load app :key Comp) does is ship some EDN off the server that looks like {:key (om/get-query Comp)}. the server then sends back a vector of things. untangled does #(swap! app-state assoc-in (ident Comp %) %) for every element in this vector, and it also puts (map %(ident Comp %) result) into :key at the top-level of the app-state

adamvh03:06:04

i think what i was missing is how untangled uses ident to do all of this

claudiu06:06:30

@tony.kay By no-op you mean it should not work on the server ?

claudiu06:06:01

The flow I’m trying to get is:

claudiu06:06:32

On initial load, on the server, 1) generate the db with get-initial-app 2) set the current route 3) populate the db with the server data 4) render-to-str the app 5) dump the db in the html 6) client loads the pre-populated db from the html

claudiu06:06:12

basically dropping the new-client started-callback.

claudiu06:06:20

probably a naive approach on server, was trying to implement like:

claudiu06:06:27

(def app-state (uc/get-initial-state ui/Root {}))
(def parser (om-server/parser {:read api/api-read :mutate api/api-mutate}))

(def ui-parser (om-next/parser {:read plumbing/read-local  :mutate plumbing/write-entry-point}))
(def reconciler (om-next/reconciler {:state (atom app-state)
                                     :send (fn [d cb] (cb (parser {} (:remote d))))
                                     :parser ui-parser}))

(df/load reconciler :all-items ui-root)
(def app-str (dom/render-to-str (ui-root app-state)))

claudiu06:06:51

Can you help me out with a suggestion on how to get this flow with untangled ?

claudiu06:06:11

Also noticed that new-untangled-client ignores the :initial-state if the root component has uc/InitialAppState is there any change this will change in the future ? To If I specify it then it will be used ?

tony.kay19:06:05

@adamvh Untangled doesn’t do normalization. Om does. Untangled merges the result from the server using Om’s merge (which in turn uses the original query, which contains component metadata, to normalize the return value). The return value can be a vector or a singleton…up to the server.

tony.kay19:06:36

Om has a function called tree->db that is the essential workhorse for normalization

tony.kay19:06:33

If you look at the metadata on the query, you’ll see that get-query hangs the component on the node of the query that was generated by that component. This allows tree->db to figure out (recursively) which components to use to normalize the entire tree of data from the server into the UI database.

tony.kay19:06:58

@claudiu Yes. You’re on the server. There is nothing to load. You’re doing server-side pre-rendering, not running the entire app there.

adamvh20:06:39

well, regardless of which layer of the stack is doing what, i think i understand what's happening, at least in the simple case of the dev-guide, so thanks for your patience and the nice video! 🙂

tony.kay20:06:59

@claudiu You could generate a data structure and emit that into the page as embedded javascript and do some magic to merge that in…but as far as I’m concerned Untangled is not meant to be run on the server this way…just initial render. You have to wait for the JS to load before anything happens. If you know something in advance on the server you could technically embed it into initial-state to get an initial render that looks pre-filled.

adamvh20:06:20

if the server doesn't know how to respond in EDN, is there somewhere i can hook into the df mutations to EDN-ize whatever it gives me?

adamvh20:06:37

or just generally to operate on whatever it gives me

adamvh20:06:05

or is that a little outside the scope of data-fetch

tony.kay20:06:42

@claudiu The initial-state behavior is for bw compat. Once you embed it in a component, it overrides the option and issues a warning. But you can put logic in the initial-state function of your root component.

tony.kay20:06:41

@adamvh There are a couple of approaches. The EDN layer is at the networking. You can plug in a custom network object into client and do what you want with the EDN of the client and the responses of the server.

tony.kay20:06:14

You could also just add functions to the server layer to speak to your app, since they are usually pretty thin

adamvh20:06:34

yeah, i had my eye more on hitting third-party API endpoints that don't speak EDN

tony.kay20:06:38

pre-existing REST services: usually make a network obj for client

tony.kay20:06:05

Also note that you can specify “which” remote, and can have more than one networking object installed

tony.kay20:06:18

loads and mutations both support that

adamvh20:06:28

yea, that seems like the cleanest way to do that. where would i look for info on network objects and hooking them for different remotes?

tony.kay20:06:34

if you’re using defmutation:

(defmutation update-thing [{:keys [param]}]
   (action [{:keys [state]}] ...local update...)
  (name-of-remote-1 [env]   ...stuff to send to remote-1...)
  (name-of-remote-2 [env]   ...stuff to send to remote-2...)
  ...)

tony.kay20:06:51

in the network namespce there is an UntangledNetwork protocol. Implement that. Mainly send

tony.kay20:06:59

see the source of the built-in one for ideas.

tony.kay20:06:53

you’ll receive the data to send, and the callback to call with the response. EDN for both. You’re responsible for talking to the server however you want, and translating the response back to EDN that makes sense for merge.

tony.kay20:06:28

for loads, load supports a :remote option that is just the name you choose for the remote

tony.kay20:06:54

the default remote is just called :remote

tony.kay20:06:08

which is why you normally use that name in defmutation

adamvh20:06:38

yea, will check it out. btw, if i take the time to figure out some of this stuff for myself and write up my understanding, is there some doc for which pull requests would be welcome?

tony.kay20:06:09

remember that there is an easy way to convert js data to clj

tony.kay20:06:35

Docs: the dev guide should have something on advanced networking already…welcome to add to it

adamvh20:06:05

ok, wasn't sure if i'd be stepping on toes by submitting pull-reqs to the dev-guide 🙂

tony.kay20:06:52

oh, I guess it doesn’t…yeah, that’s the place to contribute that

tony.kay20:06:12

The M section would prob be the place

tony.kay20:06:26

like M50-Using-REST ?

tony.kay20:06:39

or Multiple-Remotes

adamvh20:06:39

the J section is also using df/load-data in the exercises and solutions - given that i just worked through that, i was thinking i might update the solutions to use df/load-data

tony.kay20:06:52

Yeah, I’d love to get rid of those refs

adamvh20:06:26

and the solutions don't refresh on load from the server (you have to type in the text box to trigger re-render)

adamvh20:06:49

alright, well, if i find the time i'll try and submit some pull requests

tony.kay20:06:09

Note: I’m working on a combo lib that integrates the dev guide

tony.kay20:06:31

I may have already made some fixes…you’d want to open an issue and point to the problems so I can look

adamvh20:06:41

ok, will do

adamvh20:06:29

i think i'll write one issue with everything i've noticed in this file

tony.kay20:06:14

great, thanks

claudiu20:06:31

@tony.kay thank you. Will play around with it a but more and see if I can find a way to reuse the code and populate the db. There were some render cobditionals in the df/load and though maybe there is a easy built in way. :)

tony.kay20:06:16

yeah, how would I implemnent load on the server? The networking is totally different.

tony.kay20:06:34

so it is just a stub so it doesn’t crash

claudiu20:06:23

Think while playing with om-next managed to get it working with reconciled :send on the client it was a http call, on the server it was a call to the server parser directly. Was just a simple get from atom test so not sure if it has any gotchas.

tony.kay20:06:23

I see. Calling the server parser directly in the initial-state should work. all you need is a tree of data there

tony.kay20:06:52

As long as the query matches (so normalization works)

tony.kay20:06:15

now that could be a problem, I guess, since you might not want the query there.

tony.kay20:06:45

I guess you could use merge-state! manually instead

claudiu20:06:57

Will play around with it more. It’s a important for my project since i have a few public pages and it really helps with seo & loadtime.

tony.kay20:06:13

k, let me know what you do. I’d be interested in adding that to the devguide as well