This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-01-27
Channels
- # alda (21)
- # announcements (7)
- # beginners (70)
- # boot (95)
- # braid-chat (28)
- # bristol-clojurians (2)
- # cider (22)
- # clara (4)
- # cljsjs (13)
- # cljsrn (40)
- # clojure (93)
- # clojure-argentina (1)
- # clojure-art (1)
- # clojure-miami (3)
- # clojure-norway (1)
- # clojure-portugal (2)
- # clojure-russia (39)
- # clojure-sg (3)
- # clojurescript (25)
- # clojurian-chat-app (4)
- # community-development (5)
- # conf-proposals (20)
- # cursive (48)
- # datomic (39)
- # devcards (5)
- # dirac (4)
- # editors (2)
- # events (11)
- # funcool (65)
- # hoplon (95)
- # jobs (12)
- # ldnclj (4)
- # lein-figwheel (2)
- # leiningen (1)
- # om (311)
- # onyx (20)
- # philosophy (4)
- # proton (41)
- # re-frame (83)
- # reagent (49)
- # ring-swagger (3)
- # spacemacs (8)
- # yada (5)
Hi, I'm using defui inside a let block that defines a table-name variable. I just saw the dnolen talk that said that om.next defui don't have props on declaration to not risk confusing closures. First sorry my misundestanding of the implications of that declaration, and may me ask: Am I taking the same risk old om did by issuing a defui inside a let block ?
woo I have a fully functional server capable of running many queries against a SQL database https://gist.github.com/jlongster/570a9249e8648ed73a9a
@jlongster: nice!
@jlongster: looks really good
I'll post the code at some point, need to clean it up. also not a goal to do anything too sophisticated.
@geraldodev: using a def
anything anywhere other than in a top level let
is not recommended
and I don’t personally even really have much appreciation for the top level let
pattern
I'm having a hard time grokking normalization in om.next -- I'm noodling around with an app that starts with an empty state and loads a bunch of data that should get normalized like the second tutorial, but I'm not sure how to go about it.
@teslanick: it might be easier if you can describe what about normalization you’re getting stumped on
Sure: In the normalization tutorial the app loads a map and normalizes it. Do mutator functions that insert new data provide normalized or denormalized data?
they work on the raw state value which will be normalized so it’s your responsibility to deal with that
auto-normalization only happens when loading the initial data or getting new data from remotes
@tony.kay: I have fixed the problem yesterday. It was the messed up path. I pass down the props indirectly like this (child {:value child-props})
while I should pass it down like this (child child-props)
holy cow om/process-roots
just clicked for me, much easier way to transform queries for the server
@jlongster: you can briefly tell me what it does
hi guys, I encounter a problem regarding using core async to communicate between om components. I don't pass props through the channel, in this case, I just send and event to a component, then the component can transact its own states. The problem I have is, the state getting through (om/get-state this)
in the go block ( I create a go block in componentDidMount
) is out dated. How can I fix this kind of problem ?
When rendering two different views of an entity (e.g. a list view item and a details view of a User) and the two corresponding components have different queries (as they need a different selection of attributes from User), how should the queries be passed down to the Root component? Should Union queries be used in such a case? Is there another recommended way of doing that?
@tmorten: initLocalState
seems to be the right place to initialise component local state with properties.
@andrewboltachev: Any progress with routing. It is the last part of the puzzle before I start a fresh project in om.next.
@tawus: a question?
I am still not sure if set-query!
is the correct way for routing, (atleast the way some of us are using it doesn't seem the best way). I see you have been working on it. So, I wanted to know if you have found a better way of doing it.
In fact, great progress with it
and I used exactly it
haven't shared my experience yet so let's do
I'll prepare a project in ~20 min
hey @tawus it takes a bit more. I'll share link to the repo in a second
Perhaps a silly question - how do I get om.next to perform a query only when I hit a button.. passing some text from another input field? currently as the user types I am updating the component local state, then when they hit the button I add it to a parameterised query, which is when I want to run the query (hit an API). However updating the local state causes a render and hence the query to be run every time a key is pressed.
Do I need to read the value from the DOM only when the user performs the click? Just seems like there should be a nicer way
@mrjaba: Do you mean new "local state" feature by "component local state"?
@mrjaba: You can check my https://github.com/andrewboltachev/html2om/blob/master/src/cljs/html2om/core.cljs project, which is doing thing so similar to yours
@mrjaba: So does "autocomplete" example https://github.com/omcljs/om/blob/master/src/devcards/om/devcards/autocomplete.cljs
@andrewboltachev: thx for the repo link. it's not complete yet, right? guess that's on purpose and not just a missing push...
@mrjaba: And, answering your question: You would most likely read value from the DOM each change, i.e. when onChange
is fired then you would do mutation.
So I was following the autocomplete example, but instead of doing it onKeyUp I want to do it when the user presses a button
@nblumoe: Not ready, completing it now, in fact
so to take the value from the text input field on the button press.. but I was hoping not to have to hardcode the id of the input field.. which I guess isn't too bad, but just was hoping it was less DOM maniupluation/funkery
@andrewboltachev: I'll take a look at that link of yours though, thanks
@andrewboltachev: So your example is almost exactly the same as what I have.. but isn't yours running the query for each key the user enters? Mine is and I can't see how yours wouldn't be doing the same?
@mrjaba: Let me check, seriously...
@mrjaba: In Chrome's "Network" tab I see new XHRs only when I press the button
@mrjaba: This readf
is one I don't understand that good (I've taken it from "autocomplete" example). But I think this is the clue: https://github.com/andrewboltachev/html2om/blob/master/src/cljs/html2om/core.cljs#L89
(defmethod read :qc-set/by-gvm-id
[env k params]
(let [st @(:state env)]
(if-let [[_ v] (find st k)]
{:value v :remote (:ast env)}
{:value :not-found})))
@mrjaba: I know there's some brand-new "local state" feature, but unfortunantely I don't know anything about it
in yours your are using transact! which sets the app state, and in transact! it's expecting a list of components that should re-read after this has been done. In my update, I'm updating the component local state which forces a re-render (and I think re-query) each time it's updated
I think that's what's happening, but this is day 3 of om.next so I may very well be wrong! haha
for me week 4 or so in React, Om and Om Next
@nblumoe: Now I have one problem with the project. Way I did it first wasn't to good, though successful. I want to make it better and I'll figure this out
ha, okay. I am struggling quite a bit with getting routing, queries (down to root) and normalization working together properly...
@nblumoe: https://github.com/andrewboltachev/omnext-routing-one/blob/master/src/cljs/omnext_routing_one/core.cljs#L347
for me query is nil
after I set it
@nblumoe: My initial, and working solution were query
and params
functions deriving values directly from URL
@nblumoe: So, this worked like: (1) URL changes (2) You ping the root component (this set-query!
, despite of having no effect, pings it) (3) It derives it's params from current URL, i.e. js/window.location.hash
@nblumoe: Is your solution better than this crazyness?
@nblumoe: there's this crazyness working https://github.com/andrewboltachev/omnext-routing-one/
next step in the craziness: partial-app-loading trough google closure modules 😉
@andrewboltachev: nice one 😄
I'll be happy to see alternate solutions
@nxqd: @iwankaramazow do you have any?
I'll take a crack at this later this week, need to build the rest of my UI first 😛
yep the same thing... I've started to put this into prod, so, need to continue on
You aren't worried about the alpha status of Om Next for production?
Well that's just nominal. I wouldn't do things manually which are already implemented somewhere
@nxqd went to bed, sorry. a read
function can tag various parts of the ast with :query-root true
, and om/process-roots
will transform the entire query so that all the tagged roots are the new root queries, and it returns a rewrite
function that will take the returned data and transform it back into the original structure
basically, you can easily ignore local parts of the query and just send queries that the server understands
maybe a basic question but css classes on components are defined this way:
(dom/div #js {:className "splash-container"} "Splash Container")
, aren't they?Thanks
@andrewboltachev: Thanks for the example.
@tawus: Please refer to scrollback here for the details. It's not working the way I want now (and might have non-safe parts, race conditions etc etc in it). Just "sort of works"
@jlongster: process-roots
is not that well tested yet - people need to play around with it more
is process-roots
a good fit for a recursive query scenario?
@anmonteiro: Are you still planning on renaming ref to ident in the source, or did you already do some of that on a PR?
@thomasdeutsch: It is ok with them...
@tony.kay: I did it already, if you've found any that I've missed I'm sure David will be grateful for the fix
@tony.kay: this was my PR: https://github.com/omcljs/om/pull/585
k. I just submitted a PR on merge-idents, and some were missed there, so I fixed them
@dnolen: makes sense. worked great for me so far and you say Om doesn't do much for you...
@tony.kay: Ah I've seen that one. You're all set, no conflicts
@jlongster: process-roots
has a lot of unit tests, but does not flow through union queries just yet. You could look at next/tests.cljs for cases that are proven to work.
@anmonteiro: thanks!
@tony.kay: have you had to deal with async APIs ever in the read/mutate functions? currently my read function (on the server) returns an object with channels and then I walk through and resolve all of them into concrete data before sending it back to the client
I'm a little confused about how queries roll up. Let's say I have a RootView
which renders a TodoList
. The TodoList
is paginated, so it has query params. In RootView
's query, I do something like {:todo-list (om/get-query TodoList)}
.
When the instance of TodoList
I'm rendering changes its query params to go to page 2, how does that change my RootView
's query? The query appears to be based on the default, static query of TodoList
, not the query of the instance generated in render
.
@peeja: queries changes are not reflected at the root, this is something that will probably shift around as I think about it
in the meantime set-query!
works perfectly fine on the reconciler so you can sort something out on your own
@jlongster: I have not. Everything async in my stuff is in send. That said, I do sometimes mutate a marker into app state, return remote true
to get into send, then leverage that marker to figure out stuff to do that is beyond the base query/tx stuff.
I think I'm missing something, then. Isn't the root component's query the only one that actually does anything?
A) routing is a global thing, if you want it you will invent problems for yourself which Om only partially addresses
I basically want to take the TodoMVC demo and make the list paginated. I don't need the URL to change to reflect it.
I’m trying to get you reconsider some assumptions you made above in the question you asked
I thought the root view's query was the one that was sent to the parser. Is every query sent to the parser independently?
Okay, that makes more sense, then. But then why include subcomponents' queries in your own?
I see. You're saying the initial load does depend on each component rolling up its children.
@tony.kay: ok thanks. I'm running SQL behind the scenes so all functions are async. Returning channels inside a tree structure and then resolving them into concrete data works pretty well!
Huh? Isn't it a tree? The data is a graph, but the UI is a tree, and so is the query. How can it not be?
@jlongster: Oh, you were talking server-side Didn't read carefully enough
Using Datomic, and transact returns an already completed future, so just leveraging that.
@jlongster: Not sure on the implementation, but basically it must block internally.
so I'm guessing it leverages that and just blocks until it is done, then returns the future...but the future will resolve if you deref it, since the operation is done
I see, ok thanks. I think it'd be good to have an example somewhere of doing async stuff; non-blocking IO is good for server perf. maybe I can write one at some point.
(Question to the room, since David's gone…) So, then, if the RootView
(in this example) changes its params and has to re-fetch data, doesn't it risk getting data it doesn't need? Its query includes the default query for TodoList
, which gets the first page of todos, but the TodoList
it renders has already changed its query to ask for the second page.
Or does get-query
on a component which has already rendered skip over queries included from other components?
What do you mean by re-fetching data?
remote date or local?
This has probably been asked before and searched back though messages, but I'm needing a way to force my entire RootView to update and render again. Is this possible?
@dnolen: Which one? I'm not seeing it. https://github.com/omcljs/om/wiki/Om-Next-FAQ
What I'm saying is that after the list goes to page 2, the RootView
's query is still asking for page 1
(defmethod read 'test
[{:keys [query state] key params}]
(let [st @state
found (get st key)]
(if found
{:value found}
;;else go fetch remote stuff
{:remote true}
)))
easy example I find myself writing a lot
if the result of the query is available return the result from the state, else go fetch it remote@dnolen: I saw that in React documentation but didn't seem to be doing the trick. I may have it in the wrong life cycle method.
and if you want to the child’s query to get picked up you need to re-consider what I said about with your new understanding
or you use some combination of subquery
plus letting child components deal with this stuff
it’s also possible to elide already loaded subqueries as I was trying to suggest as hinted at in the FAQ
This is probably an obvious question, but for some reason it's not clear to me. Does the reconciler only know about idents that are in the current render tree? IOW, when I call db->tree or tree->db, does it only look at the current components to determine which idents to use to normalize/denormalize?
joins in the query identify where idents should be placed or swapped out for tree->db and db->tree respectively
when we encounter a query fragment with a component type with a ident implementation we invoke it
@dnolen: thanks, I think that clears it up for me. Or at least enough to write some code to test my understanding.
Would it make sense to alter db->tree
to accept underscore-containing ident references for its second parameter, as it does in its first parameter?
In this Gist below, all tests except Y3 pass in 1.0.0-alpha30: https://gist.github.com/cigitia/29497174e19d71ccec51
@tmorten: thank a lot (I found https://github.com/omcljs/om/wiki/Documentation-(om.next)#defui)
@raphael: use that as your guide...defui is really just a "wrapper" around the react component
@cigitia: @tony.kay not sure if that should work. at that point isn't that the same as (om/db->tree [:a :b] (:y db) db)
?
actually, maybe there are use cases where that would make sense
@dnolen: is this a bug? should we follow the link in (om/db->tree '[:a :b] '[:y _] db)
?
@anmonteiro: I'm torn. It "makes sense". Say I've written a parser and I reach some point where I want to use db->tree and I've just parsed a join (so my dkey is :y, and key is [:y _]). I could imagine calling db->tree using that key as the data...but you're right in that it is easy enough to just do a tiny bit of logic and make it work.
I think I may have hit this already and wrote said logic because this case didn't work...so I'm leaning towards fixing it
@tony.kay: I am also in a duality
It makes sense to write some logic, but... we might also not want to go peek into what's there, right?
the latter being the motivation for db->tree to handle it. Would there be undesired consequences?
actually if we think of it that way, it just doesn't make sense to handle such thing in db->tree. And the example should just be (om/db->tree '[{[:y _] [:a :b]}] db db)
which works as expected
it's just that an ident is data that can be followed (which is what the function does)
so either idents should not be allowed as data, or we should make sure they all work
if you put another item in the :x table above (e.g. 3), then using [:x 3]
as data probably works
@tony.kay: right, but an ident is data.
a Link might not be
a Link is probably just a query
hmmm...well, if we consider a link to be something different than an ident (which technically it is), I can be swayed back
because you allow idents in your normalized state
you don't allow links there
that's my line of thinking
so I'm actually leaning towards: not bug
link = query, ident = data
actually, ident = data & query
thanks for breaking this down with me. Won't open an issue then
hello, is this the correct channel for omnext as well (the omnext channel appears dead?)
@tony.kay @anmonteiro: Is there necessarily a dichotomy between links and idents, and, even if there is, are all lookup forms that use underscores necessarily links?
An example of when using underscore idents might be useful within data is an application I’m making. The application stores its state in the default normalized database format. However, some parts of the database must refer to heterogenous types of entities, and some of those entities are singletons.
The application has two types of tabs (similarly to browser tabs): post tabs and an accounts tab. There can be many post tabs. However, the accounts tab is a singleton; there is only ever one accounts tab. There’s a simplified example of this at https://gist.github.com/cigitia/8bcb34ffe6bda347f1d0 in two versions, db-1
and db-2
. (`db-2` is what I would desire.)
In places where tabs of either type might be referred to (e.g., the current active tab, the sequence of tabs in the user’s order), an ident to the singleton accounts tab would intermingle with idents to post tabs. Using underscores would be very useful in this case (`db-2`), wouldn’t it? It’d allow us to continue using db->tree
to denormalize idents. It would also be consistent with underscores’ existing behavior in queries.
Otherwise, we would have to use a redundant dummy ID key (such as nil
) to refer to the single accounts tab (`db-1`) every time.
In other words, underscores can be useful in data too, not just queries, when idents need to refer to singleton entities.
@cigitia: not sure that logic makes sense. if you have something that will ever exist just once, you don't need to normalize it
By “singleton entity”, I mean that there’s only one “instance” of its type, though it may still appear in many places. There are many post tabs but only ever one accounts tab.
i.e. just put your tab object directly under :ui.active-tab
right, but it still refers to the same data in your app state
so then just put '[:ui.active-tab _]
in their queries
ah.. this was not clear
nah, it makes sense to be there
wouldn't a union query help you then?
Union queries are great and make this possible at all—neither db-1
nor db-2
would be practical without them.
that's just because links inside your state are not supported
i.e. links are currently not considered data
Yep. I’m making the case that they’re useful in data and possibly worth the cost, if there is any. I’ve never really gotten yet why idents and links are considered to be two different things anyway.
I'd say a union query makes sense in this case: just normalize all your tabs under the same :tab/by-id
and either distinguish them by their type
or some other thing
@cigitia: an ident is something that is in the data, a link is something that is in the query
@cigitia: I'm sure your problem can be solved by structuring your data differently
@dnolen: I see what you mean: the default database format’s grammar is separate from the query grammar.
Nevertheless, might it still make sense, perhaps, to make idents in the default-database format more consistent with links’ syntax in this way? They already resemble each other closely, and for good reason; they’re logically similar.
@anmonteiro: I’m thinking about how to restructure my data with union queries, and I keep running into a wall. Even if I combine all tabs into a single :tab/by-id
, where could the accounts tab’s information be stored, while still being able to distinguish tabs by type in union queries?
I already had been using union queries on db-1
: e.g., {:ui.tab/order {:ui.accounts-tab/by-id [:ui.accounts-tab/x]}, :ui.post-tab/by-id [:ui.post-tab/x]}}
. This does not work on db-2
because Y3 in https://gist.github.com/cigitia/29497174e19d71ccec51 doesn’t pass.
At this rate, I think I’m going to just leave the dummy ID for the accounts tab in anyway, as well as for similar “single-ID” heterogenous data elsewhere in the database. Maybe it’s for the best; it leaves room for multiple accounts tabs to be open at once anyway, I suppose.
@cigitia: right so you might not need to restructure your data
what I meant was just using the dummy ID, as you call it
but instead of _
or nil
, use something meaningful such as [:ui.accounts-tab/by-id :accounts-tab]
are there order guarantees of multiple mutations in a transaction: (om.next/transact! this [‘(t1) ‘(t2)])
I’m also thinking about conditional remotes mutations … for instance if validation is done as part of a transaction, and that validation can update state if invalid (for display) but if valid we want to follow it up with a remote mutation. it is unclear to me if I should rely on any order guarantees of calling the mutation function (e.g. action
thunk is executed before om calls the function to get the remote
)
I think broadly speaking I’m comparing something like this 😜 https://gist.github.com/eyston/057953716bb2dff7c0ef