Fork me on GitHub
#fulcro
<
2017-12-11
>
LL03:12:28

How make fulcro working with datomic as backend db, How to use om next's

:remote
, Do need to convert ast to datalog?

tony.kay07:12:49

@tpliliang The developer's guide covers how to talk with remotes. The story for using Datomic is identical to Om Next's.

tony.kay07:12:07

The query language is a subset of Datomic's pull syntax.

tony.kay07:12:22

See the Fulcro-TodoMVC. It uses it.

LL07:12:22

@tony.kay Yes, I just read the TodoMvc, the comment say:

; Datomic's pull can handle Fulcro query syntax

LL09:12:53

Why doesn't this

(f/ui-form-field nil
                      (f/ui-input #js {:placeholder "aaaaa...."})
                      (f/ui-label #js {:pointing nil} "hahahaha!")) 
work in semantic-ui-wrapper?

LL10:12:02

the code in http://react.semantic-ui.com

<Form.Field> <input type='text' placeholder='First name' />
      <Label pointing>Please enter a value</Label>
    </Form.Field>

wilkerlucio15:12:27

@tony.kay I just noticed something using the ptransact!, seems like operations after the first are not getting the ref on the mutation, is that expected?

wilkerlucio15:12:56

component is also missing

wilkerlucio16:12:22

@tony.kay what you think about merging the tx response in the same level as the ref that initialized it? what i"m seeing here is that, when some server error occurs (for any reason) it returns an om.next/error under the value of the mutation

wilkerlucio16:12:49

if I could just read that, would be easy for me to detect an error happened and I could display some error information to the user

wilkerlucio16:12:27

right now when I add the returning my output it just goes away (not sure why, but yeah, that's on my side), but still, if we could inject that in the same ref of the component that triggered the mutation, would be great, what you think?

tony.kay16:12:51

@tpliliang That library is a simple, largely machine-generated, set of functions that simply call the underlying react semantic UI classes. I wrote it for other's convenience. I do not directly support it. Some things to try: :pointing true? It's a straight wrapper, so you should be able to look at the code and see if the wrapper is wrong.

tony.kay16:12:43

@wilkerlucio So, ptransact! rewrites the transaction so that it can run the next step (from the reconciler) when networking completes on the prior one. I guess it probably should not lose the ref and component...could pass those along as metadata on the load marker underneath I guess.

tony.kay16:12:07

On the returning. Yeah, error handling should be improved somehow. It goes away because the merge uses the query, and the query doesn't expect an error key.

wilkerlucio17:12:55

@tony.kay I remember in past, the mutation result used to be merged at the root of the db

wilkerlucio17:12:11

that seemed to stop happening on 2.0, not sure if was intentional

tony.kay17:12:46

it was intentional...merges should be handled by a merge routine, or the new returning support

wilkerlucio17:12:56

but having it on the root is not that useful anyway because it could potentially be overwritten by someone else calling the same operation, so, it's not reliable enough

wilkerlucio17:12:16

I would love to see it merged back into the ref that called the operation (when there is one, which is most of the time)

tony.kay17:12:52

So, my thought was that if you have the possibility of an error, you'd include that as part of the query on the entity, and then the server could just return it normally...nothing needed in the library. I'm open to other suggestions.

wilkerlucio17:12:32

the problem on that is it can't be generalized properly, unless you normalize in the end on the server, but requires server changes to adapt to it

wilkerlucio17:12:00

in my case my errors are pretty regular, if there is an error, the om.next/error comes there (and that's from om parser, it automatically does that)

wilkerlucio17:12:24

since I'm in a microservices architecture, I have to keep waiting for errors to happen anytime for various reasons

tony.kay17:12:42

sure, that makes sense.

wilkerlucio17:12:40

when I tried to add the "returning", my server started outputting nothing, I have to investigate why, might be something about how the om parser works, I have to play more with the parser on mutation error scenarios to understand it better

tony.kay17:12:16

so what exactly is your proposal? "returns an error" is vague. You suggesting a specific return value, or some exception capturing?

tony.kay17:12:42

or leveraging the existing exception capturing, I guess

wilkerlucio17:12:43

well, my proposal is that we always merge the mutation result on the ref

wilkerlucio17:12:53

or give an option to do that

tony.kay17:12:56

we do, but returning uses the query

wilkerlucio17:12:13

I mean, if nothing said, just literally merge the result on the ref, for example:

wilkerlucio17:12:36

(prim/transact! this [:some "ref"] [(call/operation {})] db before: {:some {"ref" {:foo "bar"}}} db after server return: {:some {"ref" {:foo "bar", call/operation {:result "data"}}}}

wilkerlucio17:12:23

this way, any operation result could be checked upon

wilkerlucio17:12:34

without having to declare a structure and match client/server

tony.kay17:12:06

why not use mutation merge for this?

tony.kay17:12:21

then you're dispatching on the mutation symbol and can do anything you'd like to state

tony.kay17:12:27

I mean, you need to react

wilkerlucio17:12:45

not sure what you mean by mutation merge, I guess I never used that, can you tell me more?

tony.kay17:12:00

Oh...Dev Guide dude šŸ™‚ I thought you knew already šŸ˜„

wilkerlucio17:12:10

hahaha, sure, let me check it there

wilkerlucio17:12:18

I need to read those again, it's a been a long time

wilkerlucio17:12:33

(I think last time I read those it was Untangled still XD)

tony.kay17:12:09

should probably update that section to specifically talk about error handling

tony.kay17:12:06

Although you do bring up an interesting point that I had not thought about: that you might want to use returning and the mutation merge trigger...both should probably happen, and I have not tested that scenario

tony.kay17:12:49

and it should have a predefined order so it is predictable: returning first, then mutation-merge

tony.kay17:12:05

I'll add that to issues to verify

wilkerlucio17:12:33

cool šŸ‘

wilkerlucio17:12:26

@tony.kay I was just trying to use the mutation-merge, but there is one problem, I don't have the ref available there to merge where I want =/

tony.kay17:12:55

Not sure I understand why you need it. The mutation affects something in your db...and you know what that is. You had to identify "which" thing or the mutation can't know what to affect...not sure why you cannot derive it.

tony.kay17:12:14

I'm really resistant to joining ref and mutations "at the hip"

wilkerlucio17:12:02

in this case for example, I have many "cards", and the card triggers it, but from the information that comes from the server I can't identify to which card the operation hapenned

wilkerlucio17:12:15

and I might have operations on multiple cards running at the same time

wilkerlucio17:12:28

I feel like the ref is a strong information that should be present pretty much everywhere

wilkerlucio17:12:41

because it enables us to know who triggered the given operation

tony.kay17:12:02

seem fragile to me. Mutations are meant to be generalizations, and ref ties you to a specific UI concern. You could easily refactor your program and have tons of things break because you moved something to a callback in a different component that relied on a ref.

wilkerlucio17:12:13

I mean, of course I can keep throwing ids around, but the framework already have that information, feels like double work if I have to keep sending it

tony.kay17:12:22

so, my personal preference is to throw IDs around, because then all of the information is encapsulated in the mutation. Makes it fully reusable, relocatable, etc. Yes, it's a little more typing, but that's rarely my concern in a library unless I'm writining a DSL macro.

wilkerlucio17:12:23

the ref is also strong, I don't have refs like that, if a component is on a ref, it should remain there, I mean, when I transact the ref goes with it, and I never change the ref of a component once it's on the page

wilkerlucio17:12:51

so seems like an obvious target to me to re-use that information knowing the caller will be able to access it (after all, that's where it came from)

tony.kay17:12:10

but software evolution is not that "strong", as you put it

tony.kay17:12:37

you really want a general function-like thing that has to rely on the context in which it is called???

tony.kay17:12:49

full-stack?

tony.kay17:12:54

through refactorings?

wilkerlucio17:12:00

I mean, Fulcro also uses refs for generic operaitons like set-props, and here I'm also talking about generic operations (generic error handling)

tony.kay17:12:23

Those are exceptions that are tightly documented as for :ui props, local to a component only

wilkerlucio17:12:30

I'm thinking: someone triggered an op, and i have an error, so I want to give that error information back to the one who called it

tony.kay17:12:48

Ah, now we're talking about something more interesting šŸ˜›

wilkerlucio17:12:11

this is very generic, could apply o anyone, and everyone has the ref to get back to

tony.kay17:12:20

so, let's not talk about refs, but instead about getting errors into the graph

wilkerlucio17:12:21

sure, getting the error back accessible to the one who called is the main issue

wilkerlucio17:12:36

I though of refs, but if you have other way to manage, I'm all ears (maybe eyes are more correct here? hehe) šŸ™‚

tony.kay17:12:04

I have some stuff to take care of at the moment...back in a bit. I'll mull it over. David Nolen had some plans around this that he never implemented. They were making the error visible on the graph in a transient fashion (the errors would be there for one render cycle, so to speak, and you'd grab them if you needed to process them). That way they didn't end up in state unless you put them there from the component.

wilkerlucio17:12:40

I've been doing something that I liked here regarding load errors

tony.kay17:12:42

Basically, the merge would merge them at the spot in the graph where they happened...but that was for queries

tony.kay17:12:48

not mutations

tony.kay17:12:52

mutations are another story

wilkerlucio17:12:55

yeah, for load I have a good story here

wilkerlucio17:12:22

in pathom, when you add the error plugin, attributes with errros get maked on the db, and the errors thenselves come in a separated map in the result root

wilkerlucio17:12:38

this map contains {[path] error-detail}

wilkerlucio17:12:00

but on my network, I just pull those errors up, so they end up in the same level as the field with error, eg:

wilkerlucio17:12:21

{:query {:item :com.wsscode.pathom/reader-error}
    :com.wsscode.pathom.core/errors
    {[:query :item] {:error "some error"}}}

wilkerlucio17:12:29

{:query {:item :com.wsscode.pathom/reader-error
            :com.wsscode.pathom.core/errors {:item {:error "some error"}}}

wilkerlucio17:12:52

this makes really easy to display errors on the client, if there is an error, the detail is right there

wilkerlucio17:12:23

and this is what triggered my idea os pulling the mutation errors to the same place, to make those as accessible as the load errors

tony.kay17:12:10

right. let me think about it a bit....back in a little while.

wilkerlucio17:12:51

sure, have a good one šŸ™‚

adamvh18:12:18

for starting a new project, does it make more sense to use the 2.0 branch of the fulcro-template repo, or lein new fulcro app?

pedrorgirardi19:12:15

@adamvh I think the lein template was already updated to version 2, so lein new fulcro should be fine

adamvh19:12:31

yeah, that seems easier to get up and running

mss19:12:37

hey all, having a tough time getting something like the following query to work in one of my fulcro components my state initial state in my root component looks something like:

{:current-user {:db/id 1
           :organizations [[:organization/by-id 200] [:organization/by-id 201]]}
 :organizations/by-id {200 {:db/id 200
                           :name "Test Org"}
                        201 {:db/id 201
                           :name "Test Org"}}
Iā€™m trying to pull the name and db/id of each of the current userā€™s organizations I think what Iā€™m trying to do inside of my component is something like a parameterized join using idents? I tried subbing in idents in the relevant places from a parameterized join example, and my query ended up looking like the following:
[({[:organizations/by-id '_] [:name :db/id]} {[:current-user '_] [:organizations]})]
unfortunately, getting an invalid-expression error, and I canā€™t seem to figure out why. any tips on how youā€™d structure a query to pull out data shaped that way? thanks in advance for any help

piotrek20:12:32

Hello! From Dev Guide (http://fulcro.fulcrologic.com/guide.html#!/fulcro_devguide.O01_Forms_The_Basics): >quote NOTE: The Forms support described in section O is still described with defui. There is ongoing work to add a simpler method of forms support to 2.0. Once that evaluation is complete these sections will either be updated or replaced with the new mechanism. There is no plan to remove this form support, but the advent of Clojure spec is leading us to what we think might be a better way of doing it. Is there any timeframe for the reworked forms in 2.0?

tony.kay20:12:10

@mss are you trying to load things?

tony.kay20:12:35

@piotrek You can look at the current proposed version on the forms-2.0 branchā€¦lots to do right now, but would appreciate feedback

mss20:12:57

nope, this is local, if thatā€™s what you mean. no remotes or external data sources for now

mss20:12:15

I have some data shaped like that supplied as initial state in my root component

tony.kay20:12:17

so, parameters are not generally what you want. Just shape your data for the structure of the UI

mss20:12:32

just to help mock and play around with

tony.kay20:12:33

in other words, donā€™t try to reshape the data with the query in the UI

tony.kay20:12:53

your db looks fine to me

tony.kay20:12:35

I assume you have an Org UI component that queries for [:name :db/id]

tony.kay20:12:03

and a User ui component that has [:db/id {:organizations (prim/get-query Org)}]

mss20:12:36

I donā€™t actually. I was going to break everything up into pieces like that once I got the overall query working

tony.kay20:12:46

then you can technically embed that anywhere with the query [{[:current-user '_] (prim/get-query User)}]

tony.kay20:12:05

and youā€™ll get current-user out in props

tony.kay20:12:12

no params necessary

mss20:12:45

that makes sense

mss20:12:55

thanks for the pointers

tony.kay21:12:53

@adamvh The template is probably going to be renamed and turned more into a sample project. Itā€™s too much to grok all at once, so the lein template is prob a better place to start.

tony.kay21:12:05

but thatnks for the reminder that I need to finish that

adamvh21:12:49

yeah, the lein project has been a much better jumping-off point; i can get cards going and make UI elements really easily

tony.kay21:12:02

you found the new videos, right?

tony.kay21:12:08

Iā€™m making more today

adamvh21:12:05

yeah, i found the new-ish(?) ones

tony.kay21:12:14

made last week

adamvh21:12:16

like from the past couple of days

adamvh21:12:47

although i haven't watched them; electing to try getting my feet dirty with my untangled-era knowledge before watching them šŸ™‚

tony.kay21:12:24

up to you šŸ™‚

piotrek22:12:26

Hi! I am trying to find a correct way to obtain the current route to highlight the current menu item in the top navigation bar (I am sorry for silly question - I am still learning). I have this router:

(defrouter TopRouter :top-router
  (ident [this {:keys [screen]}] [screen :top])
  :main MainScreen
  :settings SettingsScreen)
that I use in my Root:
(dom/div nil
  (ui-top-menu)
  (ui-top-router top-router-data))
What is the idiomatic way to query in TopMenu for the current route to get a value like :main or :settings?

wilkerlucio22:12:34

@piotrek when you have this kind of things: a parent that knows a selection, and the children where one of those are selected. What we usually do is send the some info the the selected item as a computed prop

tony.kay22:12:38

Fulcro 2.0.0-beta6 on clojars. A few minor bug fixes. Fulcro template updated to 2.0 as well.

piotrek22:12:40

@wilkerlucio I think here itā€™s not a parent that knows the current selection but rather a sibling component (TopRouter knows that, not Root)

tony.kay22:12:10

@piotrek Look at the devguide source code for twitter bootstrap

tony.kay22:12:14

there are examples in there

tony.kay22:12:28

you donā€™t have to use bootstrapā€¦those are just wrapper classes, but it is a working example

wilkerlucio22:12:49

@piotrek sure, you can send the props via computed to that too

wilkerlucio22:12:57

in a list case it would be something like this:

(for [i items]
  (some-child (cond-> i (= i selected-item) (om/computed {:ui/selected true}))))

tony.kay22:12:12

like this, right?

tony.kay22:12:52

or this one

piotrek22:12:16

Thank you - I will take a look

tony.kay22:12:31

you can also use computed, as Wilker suggests. These examples use state as reusable components. The idea is that HTML5 routing would happen out of context of a parent/child relationship, and you might have to update a number of GUI things all at once.

tony.kay22:12:01

and the GUI things might not even be closely related in the DOM

tony.kay22:12:00

one could argue that using state in more than one component to stand for the same thing is duplication (and Iā€™d agree). Using link queries is another alternativeā€¦query for the routerā€™s state from the router table and ā€œlookā€ is the better way perhaps

tony.kay22:12:02

fulcro.client.routing/routers-table is a var holding the keyword of the router table name. So a query like this: [ [r/routers-table :your-router-id] ] will get you any routerā€™s dataā€¦

piotrek22:12:15

Oh, so it looks that I would need to maintain a sub-graph holding the currently selected screen, independently of the [:fulcro.client.routing.routers/by-id :top-router :fulcro.client.routing/current-route] path

tony.kay22:12:44

unless you use that last trick I typed while you were typing that šŸ˜œ

tony.kay22:12:04

if you query for the routerā€™s state, you can just use current-route

tony.kay22:12:15

so, at least 3 decent ways to go about it. That last one is probably best overall.

piotrek23:12:48

OK, so I went with the ident based query: [{[r/routers-table :top-router] [::r/current-route]}] and it binds current-route local var to a value like {:screen :main} which is the value from [:main :top] sub graph (a state of my MainScreen). Is there a simple way to unpack the :main value from it? (I am using :screen in the TopRouter ident)