Fork me on GitHub
#om
<
2016-01-21
>
sjol01:01:26

@thosmos: thanks you for the insight. I am passing a cursor to my reforms forms but data in that cursor has been set prior to the form and in that case it gets erase, in essence I just want to use the form as an update form. What would an "Edit customer" look like?

jimmy03:01:38

hi guys, I have a question regarding mutation in om next

jimmy03:01:38

will the the mutation function get hit again ( like read ) with new state after the send function gets results from remote ?

jlongster04:01:44

is it encouraged to normalize data on the server before sending it to the client? seems to work to send denormalized data and merge it in, but the obj will be bigger

yaniv04:01:02

hey james. don’t know the best practice there. what are you doing with om next? i saw your talk on redux with firefox. very cool

jlongster04:01:23

@yaniv thanks, much more to come and hope to show off a lot more usage. I'm just doing a side project to solve a need, and good to know these patterns for our work too

yaniv04:01:15

yeah om next shares a lot with redux. i’m gonna shoot you a PM to not clog the channel

jlongster04:01:05

well, maybe some basic concepts but there's a lot more in om next simple_smile

yaniv04:01:55

yeah. just the single state atom really.. and normalizing all your data. which i guess falls out of the single state atom

andrewboltachev04:01:57

@nxqd: I'm not sure, but if your function is just {:remote true}, what's reason to hit it? Seems like mutation function (on the remote parser) is "change state and go", i.e. it doesn't return anything. And after mutation you would need to fetch the changed keys yourself. Even :value :keys don't work, as guys there said it's just for documentation reasons (which I'm confused about still).

jimmy04:01:25

how do you handle this example : user > login . You want to check for error returned ?

jimmy05:01:00

for now I do handle it in the recursive read function since the read will be hit. hmm I'm confused about the :value and :keys as well. I'm trying to find a way to force rerender after mutation, I thought keys would be the one we need but it doesn't seem to work.

andrewboltachev05:01:36

@nxqd: good question. Btw, is it the same for any kind of validation, not just for login form? and yep, seems that you can actually only solve it by reading straight after mutation. and dependant components would be re-rendered then, woldn't they?

andrewboltachev05:01:21

though, well... error for particular user is client-only sate

andrewboltachev05:01:29

...just wanted to say: that's how you can receive data from the server, but that's just "read" they're doing

jimmy06:01:48

@andrewboltachev: I mean I want to check the response from server.

andrewboltachev06:01:21

@nxqd: but is login operation a mutation operation? from server point ot view?

jimmy06:01:51

yes it is

jimmy06:01:49

the problem I encounter is : for example I mutate 'user/signin ( I have this mutate on server and frontend as well )

jimmy06:01:58

I got results into 'user/signin on my application state. And of course all the read function would be hit again this time, I manage to get the data out just fine ( I think it would be cleaner that we can get the data in the same mutation function on frontend.. )

jimmy06:01:24

regarding local mutation, after swap the application state, it doesn't rerender the app T_T ( :keys problem you said above )

andrewboltachev06:01:15

so, on the server is 'user/signin in the db somewhere?

jimmy06:01:42

hmm I haven't tried to read app-db on server . I just care about the app-db on frontend.

andrewboltachev06:01:07

what do you mean "app-db"?

jimmy06:01:36

hmm, I might misunderstand you. db you mean something like datomic ?

andrewboltachev06:01:52

yep, just the database, i.e. persistant thing

jimmy06:01:11

'user/signin does interact with db

andrewboltachev06:01:10

so your app kinda knows "who's online"

jimmy06:01:54

you can check the om-next-todo example for server example

jimmy06:01:11

it doesn't work and a bit outdated but all the things are there ( you might not be able run it as well )

andrewboltachev06:01:40

yep I did try to run it

andrewboltachev06:01:59

but is there anything like that? i.e. auth

jimmy06:01:15

it just a mutation. once you understand how it interact with the server, you can build it easily.

andrewboltachev06:01:49

ok, I'll check it out. the only serious thing I did in Om Next so far is this https://github.com/andrewboltachev/html2om and it works w/o mutation just like "autocomplete" example

andrewboltachev06:01:30

In the meantime, on topic of "where all data goes etc" there's this video: https://www.youtube.com/watch?v=IlNrmKYA7Ig

andrewboltachev06:01:44

I didn't watch yet, but should be worth it

nano10:01:27

@anmonteiro: Cool, that (applied something similar to your paste last night, which I guess is what you filed as #582) seems to take care of my loss of query on figwheel reload.

anmonteiro10:01:05

@nano: hah, cool! Also whenever #583 is merged you can drop the setPrototypeOf line

jlongster15:01:37

I don't have a good feeling about how typical it is to "transform" queries before sending them off to the server. do servers typically handle "raw" UI queries, meaning it knows a lot about the various keys used by components in queries, or is it typical to convert queries into a simpler format before sending them off to the server?

jlongster15:01:18

my impression is that usually they aren't transformed, but that seems like the server ends up being aware of the component structure? guess I need to keep building this and feel it out

nano15:01:29

@anmonteiro: Problem is that it resulted in another problem. I have :categories that I parametrize to fetch different XML urls, but now that I keep state, it won't fetch more than the first one. Need to figure out how to store the results based on the params instead, or perhaps more crude.. just nuke data when leaving the component.

anmonteiro16:01:47

@nano: or also gather-sends, queue-sends! and schedule-sends! on figwheel reload

anmonteiro16:01:51

would that work?

jlongster17:01:03

ok I think I figured out how to do queries in the server, one last question: should I make sure to send back normalized data? otherwise the payload is going to be a lot bigger, but that means the server needs to be aware of the normalization format

dnolen17:01:49

@jlongster: it’s up to you what you want to do

dnolen17:01:58

letting Om normalize for you is easier of course

jlongster17:01:46

@dnolen: ok, didn't know if anyone had any recommendation from experience. but I'll just do what feels right and see how it works!

iwankaramazow20:01:47

Does anyone know if it's a good idea to make internationalization (basic translation/different languages) components where the text it needs to display forms the query that gets send to the server?

tony.kay20:01:00

@iwankaramazow: Hi. We're doing i18n in our app with Om Next. Good idea is relative. Here is how we handle it:

tony.kay20:01:20

- We use a GNU gettext approach for UI bits (strings that are part of the UI).

tony.kay20:01:35

- For data the user input, it just needs to be unicode...so no "special" query...it is a scalar string

tony.kay20:01:01

- For translations the user enters (we allow our user to create a thing that itself is internationalized) then we persist those and need queries.

tony.kay20:01:39

So, the only time we put them in the queries is when it is persisted data, and in our case we don't need to bother with choosing the locale, since they are editing all of them at once...so multiple fetches make no sense

tony.kay20:01:03

The first, we will be open-sourcing soon as part of helper libraries that stack on Om Next

tony.kay20:01:37

We do use modules to load UI i18n strings as a bundle

tony.kay20:01:16

So, for example, but button might look like (button nil (tr "Push Me"))

tony.kay20:01:30

where tr is a function that both marks the string for extraction, and displays the translation on the screen

tony.kay20:01:46

we also made a lein plugin for doing the extraction step

iwankaramazow20:01:02

Interesting, thanks for the response!

anmonteiro21:01:41

I wrote about the recent questions / developments of writing reloadable code

anmonteiro21:01:07

hope it serves as a reference for everyone who's trying to do it

tony.kay21:01:36

@nano: Also seems like you could make a hot-reload mutation that you could hook to the figwheel callback (e.g. (app/hotload))...that could modify your app state (if you need)...but that results in both load and remote parses. So it could just be a no-op...heck, if you have a "default" multimethod, you could just say anything and it would have that effect.

nano22:01:41

Well.. my problem isn't any longer reloading. But a problem that existed before, as now that I have reloading I had to add back-navigation in my hierarchy, and noticed that I load data for components with other parameters as my :read only checks if for example :category exists, when the current :category is really (:category {:section "blabla" :view "bleh bleh"}) .. so if I want to open another section, I can't.

nano22:01:31

So I guess I want my app-state to be more like {:categories {:foo [item1 item2 item3...] :bar [...]}} not sure how to do that though, as the foo and bar are dynamic results from previous reconciler reads.

nano22:01:50

and I'm also not sure I want to build up app-state indefinitely, I will probably attempt to do that, as it's unlikely that people will browse through the whole app, and going back to an already loaded category is more fun than waiting for it to load.

nano22:01:13

Also been pondering if I want to introduce DataScript with local storage, and somehow re-fetch the remote data on each access, and if there's a diff -> update the UI. Would be a very nice and fast experience in my mind at least. But I can't even begin to graps how to do that yet.

tony.kay22:01:05

@nano: before you start "optimizing" with DataScript understand that a query engine is many order of magnitudes slower than raw map reads. Just noting.

nano22:01:05

All data displayed is read from a remote server - so with local storage it would be faster than that when restarting the app. But sure, during runtime it would be faster to access the data only from the app state. It's not much data though. Each view loads data on somewhere from 10 to 30 items, and each item doesn't have a lot of props.

tony.kay22:01:46

Don't have the spare cycles to understand your app-specific use-case. sorry.

nano22:01:52

You could think of it as Netflix on Apple TV or a similar device, for me it's a Swedish Television app on my Samsung "Smart" TV.

nano22:01:00

That kind of navigation and content loading.

tmorten23:01:44

Hello all...just want to make sure my assumption about tempids are correct. In looking at the Om next source, :id-key needs to be in the config of the reconciler in order to take advantage of the merge of tempids to realids. And this is a global identifier for every "entity" in the system correct? i.e. I have a :person/gid identifier and a :company/gid identifier therefore I need a custom merge to map those tempids to real ids. If I had one standard entity identifier, like :db/id, merge would just work...

dnolen23:01:43

@tmorten that is not correct

dnolen23:01:57

:id-key is just a convenience if you can provide a global id key

dnolen23:01:25

the other way is to return enough of the updated entities in your response to rewrite the ids of the original entities

dnolen23:01:54

Om Next takes care of fixing references

tmorten23:01:16

@dnolen: so if my parser server side is only creating one entity and responds {:tempids {[:person/gid :om/id[]] [:person/gid "realid"}] the tempids wil not get merged until more entities come in?

dnolen23:01:40

@tmorten that’s not what I said

tmorten23:01:55

@dnolen: sorry, I guess I'm not following you when you say "return enough of the updated entities in your response"...

dnolen23:01:25

Om Next has special merging behavior for top level ident values

tmorten23:01:02

.i.e. [:person/by-id ...] ?

dnolen23:01:09

in the response if you have stuff like {[:foo/id temp] {:foo/id real}}

dnolen23:01:18

these will get merged in

dnolen23:01:37

so if you cannot use :id-key do this instead

tmorten23:01:09

@dnolen: I'm tracking now. Thanks.

dnolen23:01:27

to summarize

dnolen23:01:35

:tempids is about fixing links

dnolen23:01:48

other pointers

dnolen23:01:58

:id-key is about fixing the original entity

tmorten23:01:17

@dnolen: Not gonna lie. Sometimes the Om.next source code makes my head/eyes woozy. Nice work for sure.

dnolen23:01:20

if you cannot use :id-key you have other options

dnolen23:01:53

at least you can rest assured there’s 95% chance I’ve already considered all of your problems

tmorten23:01:19

So to sum it up: If in my mutation say {:value {:tempids {[person/gid temp] [person/gid real]}}}, I'll be golden?

dnolen23:01:58

again that's not what I said

dnolen23:01:18

that will only fix pointers to the old id

tmorten23:01:35

@dnolen: I've been up late so forgive me 😞

dnolen23:01:02

idents pointing to that entity will litter your application state

dnolen23:01:11

those we can identify and fix

dnolen23:01:22

because queries tell us this

dnolen23:01:39

but how can we fix the id value in the original data

dnolen23:01:05

or your backend needs to pass update information

dnolen23:01:14

as I’ve already described above

tmorten23:01:34

so I need to send back the entity essentially. That is the one that will be in the top level [:person/by-id ] map, [:person/gid tempid] {:person/gid realid :person/name ".." :person/address ".."}

dnolen23:01:40

@tmorten: you don’t need to send back the entire entity

dnolen23:01:47

just the new id value

tony.kay23:01:52

@dnolen: @tmorten We just ended up doing a clojure walk replacement for tempids...they have a type, so it is trivial to rewrite them all at once safely.

tony.kay23:01:10

also alleviates needing to know the ident keywords

dnolen23:01:44

that’s also possible in some cases

dnolen23:01:01

using the query means less work since you look at less

tony.kay23:01:24

yeah but the responses are not frequent on a user time scale...so don't mind t aking the perf hit...js vm is fast

dnolen23:01:37

it just depends

tmorten23:01:44

@tony.kay: what made you go that route?

dnolen23:01:50

already seen cases where the few places where we walk blindly is a perf problem

dnolen23:01:07

but yes - plenty of apps where this isn’t going to be a problem

tony.kay23:01:09

@tmorten: It alleviated all of the problems with possibly having more than one id key on state objects. Also, our app state is not huge, so the performance implications are fine.

tony.kay23:01:33

also simplified the server/client comms, since we can make tempids be something simpler (just the ids, no idents)

dnolen23:01:42

tempid migration is an intentionally pluggable thing - so if clojure.walk works for you there’s nothing wrong with doing that instead

noonian23:01:46

@tony.kay: I haven’t thought about it enough, but I suspect process-roots would ideally be generalized into some sort of clojure.walk like thing that also lets you pass context monadically during your walk and return that with the transformed result. I believe if you had such a thing, the current behavior could be implemented on top of it.

tony.kay23:01:43

@noonian: Not sure it would be very easy to understand..don't really want to think abt it simple_smile

tony.kay23:01:50

not using process roots either, it turns out

tony.kay23:01:38

FYI, I'm going to clj west...if they have breakout sessions I'm likely to offer giving an overview of how we've used o.n.

tony.kay23:01:58

so anyone interested in seeing some early production code/use cases might find it interesting