Fork me on GitHub
#om
<
2015-12-21
>
mking00:12:39

let’s say i have two components, a search terms field and a search result list, that aren’t ancestors. I want the terms to change the displayed search results, but i don’t have access to the search result list's set-query in the terms component. I was thinking maybe I need to move the terms into the app state atom and have the search result list’s query look up terms from the state?

mking01:12:33

or I guess the common parent can call set-query, but the two components might be pretty distant from their common parent in the extreme case

thosmos01:12:20

@mking: I think it's reasonable to have a :current-search at a common query ancestor, possibly the root. Either way, the common ancestor will pass the search terms down to the results component via props. It's also a good place to pass a callback to the search component that runs a transact! on the common ancestor.

jplaza02:12:22

That’s kind of the principle I always use. Take the state as up in the hierarchy as possible, anything else worth considering?

rhansen04:12:38

@jdubie: I should've been more clear. I'm more interested in what happens on the frontend.

jdubie05:12:32

If there is an error on the server {:login/error "bad password"} will get merged in your local state. Your transaction specifies :login/error as a read key so it will get re-read. Then in your component you should make sure :login/erroris in your query. Then if it is not nil render a modal or error message.

rhansen05:12:32

One more question. To reset this error, that would have to be a mutation as well, right? Say I switch between the register and login form, to clear the :long/error, I would have to call a mutation on "componentDid(Un)Mount"?

smeister07:12:55

@rhansen You could clear the error with a transaction in the login component's componentWillUpdate method and e.g. store it in it's local state to display it in render. Instead of using a shared atom on the server you could also return something from the action of the mutation and write a custom merge function to get it into the state as error marker.

smeister07:12:31

I would also consider using JWE Tokens, then your login could be done as parameterized read instead of mutation and everything would get a bit simpler.

smeister07:12:56

@jdubie you could try to use the total query approach and instead of changing the query change what is read inside of the read functions. I have done set-query in a lot of places and switched to having mostly static queries (except top level routing) and i think this simplifies architecture.

smeister07:12:51

I might be wrong here but i think this is also more performant as using set-query leads to a re-index

nblumoe07:12:02

@jplaza: would you mind giving an example how println in the mutation function broke re-rendering? Was println the last call and thus the mutation function returning nil? Or was it something else?

mking09:12:21

is it possible to combine parametrized reads and subselects? for example, if I’m doing a search, my query is [(:search-results {:query ?query)]. each search result has title, description, and url, and i’d like to only pull out title and url.

anmonteiro09:12:22

@mking: [({:search-results [:title :url]} {:query ?query})]

mking09:12:43

@anmonteiro: thank you. that is perfect. just curious, where did you find the syntax?

anmonteiro09:12:17

@mking: I posted it a while back

mking09:12:55

that’s great. i will definitely review that talk.

anmonteiro09:12:22

In case it's helpful

mking09:12:23

ah great, ill take a look

jplaza14:12:48

@nblumoe: No, I actually was just printing and then returning the appropriate map. I’m thinking it’s figwheel related. I will build and run my project next time w/o figwheel next time before posting something here.

danieljomphe18:12:13

@jplaza: thanks for asking the following question, changing onKeyUp => onChange solved it for me too. https://clojurians.slack.com/archives/om/p1450637198007592

danieljomphe18:12:15

But now I'm left wondering how it is that when we type text into the text field, it... appears on the page (in the field). There's no mutate parser provided to record that app state and make it reflect on the UI...

danieljomphe18:12:25

In all the other tutorial-level apps I tried, if there was no mutate parser in play, what I was typing on my keyboard in a text input field wouldn't appear in the input field unless I made sure that a mutate parser was used on onChange.

danieljomphe18:12:18

IOW: I must have got something very wrong about React's event handling model.

hmadelaine18:12:00

Hi @danieljomphe: what is your question exactly regarding the Autocompleter tutorial ?

wilkerlucio18:12:43

@danielstockton: the reason you are getting this unexpected behavior is that the Om input fields are wrapped and manage internal state

danieljomphe18:12:46

Hi Hiram, seeing nothing happened when I typed in the autocompleter input field, I had started writing what I thought was forgotten in the tutorial: a mutate parser to handle writes in the input field so that they would be persisted into the app model, and thus reflected back to the UI in the input field. So seeing now that with a very simple change the Autocomplete UI works and doesn't necessitate at all mutation of the app state, I was left wondering (and still am)

hmadelaine18:12:20

@danieljomphe: There is no mutation in this example but a read that is called because of the call to

om/set-query!

wilkerlucio18:12:35

sorry, I may misunderstood you, your question is about the om parser, the react event model, or something else?

danieljomphe18:12:16

I'm sorry, I'm not even sure which part I'm not understanding properly!

wilkerlucio18:12:26

I believe it's better if you try to learn each piece by piece, following the tutorials by each word until you are familiar with the concepts, are you familiar with React?

danieljomphe18:12:59

I might need to resurrect the example minimal app I had written last week: a single text input field with only a read parser. When I typed into that field, my characters wouldn't appear in the field. From that, I deduced I needed to complete the loop by implementing a mutate parser. My faith was rewarded.

hmadelaine18:12:02

Whenever you type in the input, there is a call to om/set-query that triggers a call to read parser with :search/results. This in turn triggers a remote call

danieljomphe18:12:05

I have read all the Om Next tutorials and tried almost all of them in the REPL. Until today, only the Autocompleter I wasn't able to make work... ok I'll read about controlled components b/c it's clearly an issue with control I have trouble understanding

hmadelaine18:12:05

@danieljomphe: if you use an input with the attribute :value, the component is said controlled and you have to use :onChange to set the value.

danieljomphe18:12:50

Oh I get it... the autocomplete example input field doesn't get its value from (om/props this) like all the other fields I had handled until then

danieljomphe18:12:56

So it's uncontrolled

hmadelaine18:12:29

this is a controlled input

hmadelaine18:12:55

it uses a :value attribute and :OnKeyUp but this does not always work and we use :onChange.

danieljomphe18:12:29

ok so finally, I think I understood the react event model quite properly, but not how Om allows things to be hooked. If I hook :value with om/props, things happen very differently than through e.g. om/get-params.

danieljomphe18:12:56

Ok, the world can continue on its course, I see how things are symmetric in the Autocomplete tutorial too. Thanks Hiram and @wilkerlucio. (And I'm going to read up on React some more.)

wilkerlucio19:12:41

hey people, I published a tutorial explaining how to integrate service databases (like http://Parse.com) as a remote read, hope it may help you write your own parser using async code https://wilkerlucio.github.io/om-cookbook/#!/om_cookbook.Parsing_Service_Databases_as_Remote

wilkerlucio19:12:40

initially I was writing it as part of @tony.kay Om tutorial, but we decided this fits better a cookbook format so I started it, if you guys wanna contribute with other tutorials please fell free to send pull requests to https://github.com/wilkerlucio/om-cookbook

sventechie20:12:52

I’m looking to make (or reuse) a countdown timer with om.next — I found this nice example with om current: https://github.com/madhuvishy/cheating-countdown/blob/master/src/cheating_countdown/core.cljs but not sure how involved it would be to port to next — is there a good timer example around written in om.next already? (Google hasn’t helped me)

danieljomphe21:12:33

In Om Next tutorials, one thing that was not clear for me is how one should specify the query of a root component whose sole purpose is to compose multiple subcomponents. E.g. a dumb example:

(defui FirstName
  static om/IQuery
  (query [this]
    [{:person/props [:db/id :person/first-name]}])
  
  Object
  (render [this]
    ...))

(defui LastName
  static om/IQuery
  (query [this]
    [{:person/props [:db/id :person/last-name]}])
  ...)

(def first-name (om/factory FirstName))
(def last-name (om/factory LastName))

(defui Names
  static om/IQuery
  (query [this]
    [??? can't this be left as an empty vector? ???])
  Object
  (render [this]
    (dom/div nil
             (first-name)
             (last-name))))

(om/add-root! reconciler
              Names (gdom/getElement "app"))

dnolen21:12:49

@wilkerlucio: eventually we need to put together a new community run cookbook under the omcljs GitHub org

wilkerlucio21:12:48

@dnolen: sure, we can move the content anytime, just let me know when you wanna it to be done

dnolen21:12:44

@danieljomphe: Names needs to grab the queries from its child component classes

dnolen21:12:56

so no, it cannot be empty

danieljomphe21:12:21

Ok, thanks Sir David; I'll try that again (tried quickly last week when I was fighting with other stuff also)

iwillig22:12:54

I have a question about temp-ids in om.next. My understanding is that a temp-id is something I can create and then use to insert into the new object into my local client database, When I attempt to insert the the new object into my remote database, I return a mapping of the temp-ids to the real remote db ids. Om.next will then remap that object with the remote id. Is that correct ?

danieljomphe22:12:03

@dnolen: Still trying to merge correctly my subqueries... with that said, I was under the impression that Om Next automatically merged all component queries into the full query. What you're telling me, is it specific to brainless Roots like that of my example, or should we always recursively compose each component's subcomponent queries?

dnolen22:12:41

the answer to “is X implicit in Om Next"

joshfrench22:12:03

@iwillig: that’s the gist. you should be returning a mapping of temporary ident tuples to permanent ident tuples

dnolen22:12:11

@danieljomphe: there is no magic there are no helpers

dnolen22:12:14

construct the query

joshfrench22:12:47

{[:item/by-id “temp-id”] [:item/by-id 1]}

joshfrench22:12:59

or whatever your ident structure is

iwillig22:12:06

oh i see, the indent tuples

iwillig22:12:16

thats what i was doing wrong

iwillig22:12:18

it should be like {:tempids {[:item/by-id "temp-id"] [:item/by-id 1]}} ?

iwillig22:12:30

or just {[:item/by-id "temp-id"] [:item/by-id 1]}

joshfrench22:12:27

the return value from the parser should be shaped like this:

{:action (fn [] …)
 :value {:tempids {…}}

firinne23:12:21

Hey there, new to both Datomic, Clojure, and Clojurescript as a whole, also learning Om, and have been trying to figure out if there is a set of things a person must learn to get a sort of Hello World live on the web backed by datomic. I heard some people here were working on that. So far here is what I’ve got Compojure/Ring: Handle requests — ping the db (used the om intermediate tutorial for the old om for this, and the book Web Development with Clojure) Datomic Queries — http://learndatalogtoday.com was most useful resource, I got some value out of the day of datomic material but couldn’t find some answers I felt I needed since most written stuff seemed to be for java. Om next — om next devcards Docker — using Docker’s networks you can name a container to have a particular hostname that other containers will point to — I’m starting with datomic free, since I know how to make that work locally, and want to get this ironed out before going onto datomic pro. Currently I think I’ve almost got the full stack connected, I’m just trying to figure out the best way to compile an app using lein uberjar without having it try to connect to the new host for my production db on datomic. Might anyone here have some examples of how one might do that. Or just an explanation of how one uses the component library to handle db connections during compilation of an uberjar?