This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2015-11-06
Channels
- # admin-announcements (59)
- # announcements (1)
- # beginners (67)
- # boot (140)
- # cljsrn (8)
- # clojure (70)
- # clojure-berlin (18)
- # clojure-dev (7)
- # clojure-russia (53)
- # clojurescript (124)
- # clojurescript-ios (3)
- # clojurewerkz (2)
- # clojurex (10)
- # code-reviews (42)
- # cursive (9)
- # datomic (2)
- # editors-rus (2)
- # emacs (5)
- # events (1)
- # hoplon (35)
- # jobs (8)
- # ldnclj (7)
- # lein-figwheel (34)
- # luminus (1)
- # om (410)
- # onyx (22)
- # overtone (19)
- # portland-or (6)
- # re-frame (1)
- # yada (4)
@adamfrey your simple question had way bigger ramifications than I originally considered
Hello guys, hello @dnolen , so I took time to clean up a bit, https://gist.github.com/leontalbot/1d57bb05c063a989757c
when I toggle first question radio button I get :
[ 11.488s] [om.next] #object[votepourca.omnexttest.Answer] transacted '[(selections/update-radio {:value value, :name name})], #uuid "35d87a1d-a354-4dc3-9bea-967ab9c6e470"
next.cljs?rel=1446568734541:905
Uncaught #error {:message "No queries exist for component path (votepourca.omnexttest/Form votepourca.omnexttest/Question votepourca.omnexttest/Answer)", :data {:type :om.next/no-queries}}
And the mutation doesn't do anything.
Anyone? probably a newbie mistake but can't find it!
Thanks in advance!!
(Note: when I click a second time on any radio button, I don't get the error message, only the transacted trace, but again nothing changes.)
I updated the example
by adding a subquery :a -> {:a ~subquery}
for answers in Question UI I don't get the error message
(defui Question
static om/Ident
(ident [this {:keys [id]}]
[:questions/by-id id])
static om/IQuery
(query [this]
(let [subquery (om/get-query Answer)]
`[:id :type :label {:a ~subquery}]))
But the mutation doesn't work, and I loose my radio button props such as type or name so that I when I toggle a radio button, it changes in regular text input...
i’m trying to build a simple example that uses om/subquery
to fetch data for the currently displayed view. this seems very similar to @bplatz’s question about an idiomatic way to build up queries for only rendered components. Basically on demand fetching for only what’s visible.
the example linked to below has a mutation that modifies :route
then renders a different component. at this point the repl shows the Root
s query has been updated but it doesn’t re-render. i admit it seems dumb to have some state change, render, then render again because your query has changed because you mounted a child ref’ed by a subquery. however, directly changing the query directly isn’t a good option because i want an unrelated component to be able to update :route
via a mutation and cause this component to render a different view.
interesting pieces from example here:
https://github.com/jdubie/om-next-router-example/blob/master/src/om_router/core.cljs#L116
https://github.com/jdubie/om-next-router-example/blob/master/src/om_router/core.cljs#L136-L141
I have an app which can be viewed in multiple languages (English/Chinese). So I store the current language in the Root view - in local state (initLocalState?). Or should that be shared? How do I ripple the selected language down to the child views? In props, query params, shared? Help! Thanks!
@leontalbot: I reported the same in an earlier comment. I think there might still be an issue with components 3+ levels deep but a simple solution is not to transact from the Answer component. Instead make a callback to a computed fn from Question. This should fix it.
take a look at my description from earlier this week for more details since there I used a slightly different fix
@simonb: sorry don’t have time to explain how to get om-next-demo running. Sounds like you want to look at :shared
which I fixed up yesterday. Not in a release yet though. You will need to install from master.
@leontalbot: your example is also still too cluttered for me to consider
Hello ! Is it me or there is a problem in the last Om-Next cut with the :shared and :shared-fn options ? There are optional but it fails at the expression :
(when (contains? config :shared-fn)
((:shared-fn config) data)))
@hmadelaine: hrm what’s the bug there?
@dnolen Cannot read property 'call' of null
(contains? config :shared-fn) returns true
@hmadelaine: oops right
@dnolen thanks. I'm reading the source. I think I have to use :shared-fn so can I change to reflect (say) a change of language. I think, :shared-fn gets passed props - props are immutable (right?). So, I'm just wondering how to get the change into :shared and how to propagate the change down to the children. Is this right or can I just use :shared (not use :shared-fn) and change the language key in :shared. Thanks!
@hmadelaine: fixed!
@dnolen: thanks !
@dnolen can a component modify its own props? For example, the root component is inited with props indicating a language of English. Then the user selects Chinese, how should I get this change into the root so it ripples down to the children? Thanks.
@simonb: The root component gets its props via its own query. So you could have it query for [:app/lang ...]
. The implement a read
method for :app/lang
and a mutate method for 'app/set-lang
that changes :app/lang
in the app state. Then, use :shared-fn (fn [props] {:lang (:app/lang props)})
. When you want to change the language in your app (e.g. by clicking on a button), kick off a transaction like this: (om/transact! '[(app/set-lang {:lang "en"}) :app/lang])
(with ' = backtick).
So, props == query. Is this the same for all components? Does query always get added to props?
@simonb Yes, if you implement it correctly it is. :shared
and om/computed
are ways to pass information outside of query if necessary.
But beyond the root component, you are responsible for passing the proper props down to each component according to their query contract. There isn't magic in there that will do that for you.
@simonb: props = query result (your responsibility to pass down the results from the parent) + computed (for e.g. callbacks, stuff that is not part of the query)
@jdubie I've been thinking about the best way to do this. I think ideally the router should handle modification of the query, and you sort of need the selection to happen outside of IQuery
, as you want the query modified prior to it being passed to the parser. One idea is to use a key identifier for the route node components (similar to naming a interceptor in Pedestal, for example). If the query join in IQuery
utilizes the same key, you could dynamically select the parts of the query that are relevant to the current route.
But it is a problem I feel is necessary to solve, at least for my app, and so far the methods to do so feel hacky and confusing... so I'm still working on figuring out the best way.
The method I'm describing would require a route component for each node in a nested route. You'd want the query joins to be exclusive of each other, and no other parts to the query except the mutually exclusive subcomponents.
if the queries are dramatically different and need coordination why even bother changing queries over just changing components
over whatever solution you’re mulling about Om Next and your interpretation of the solution
it just makes too hard to understand if there’s something missing or whether it’s another documentation issue
In the simplest of terms I can produce, the need is a nested data-driven router that only selects the bits of query that are relevant for the current route.
@bplatz & @jannis thanks. So, env in the read method of the parser is props? Or includes props? I'm trying to understand the query contract's relation to props on components. query returns a datalog expression, which gets passed to read, read also can access props for the component. Is that right? Thanks.
@bplatz: right but I don’t understand why you need this - what problem is this solving?
@simonb No, it is map that has the things you pass into it allowing you to get the props you need, based on the IQuery
you declare.
(this is an honest question btw, just trying to understand what actual advantage you are trying to achieve)
@dnolen I come from the enterprise software space, so our apps have everything from analytics, workflow management, financials, etc. I simply want to ensure the entire app isn't loaded. The root component query, without further manipulation, contains everything the app could ever do.
right so this is far into the category of things that Om Next does not care about and will never care about
why not provide you own root class thing over defui that automates all the bits you will need
this is a problem I actually care about - are the Om primitives composable enough to accomplish higher level framework goals / abstractions
@bplatz: I think (from reading the om source) it includes [:state :shared :parser :logger]
@dnolen: my own root class is what I proposed above as a router, it would manipulate query from the outside.
A delay
I think would be a nice addition, however for this particular case it may not be enough. Just the query graph itself could be significant, and it seems streamlining that to the relevant bits would provide more efficiency. But I don't really know yet, as none of this has been tried.
@simonb: Yes, and :state will contain your data, which you provide. I think a read through the wiki overviews is the best way to provide you context for this. I'd tackle that before reviewing source.
@dnolen: I have two questions for you. 1. No ideas how to use mixins let React with om. next, whether such a question? 2. Use of third-party components React?
@a.espolov: not interested in mixins
@dnolen I think think more dynamism in IQuery would be ideal. Perhaps if you could also return a function with just :shared passed in, then you'd be able to put your route information into :shared and return just the parts of the query necessary. You shot down the idea, and probably for some reasons that are not clear to me, but in the interest of describing what could be a simple solution to me, that is it.
in general not going to spend much time on feature ideas if I cannot understand the problem
but I’m happy to work out what the real underlying problem is and come up with general solutions that cover a wider set of use cases
but as long as thing keep getting framed in terms of solutions I suspect I will continue to have conceptual difficulties where I would like to be of some help.
OK, that is a reasonable stance. I think the problem has been beat down enough and is understood, but please correct me if I'm wrong. I'm thinking in solutions now because I need to come up with one. If I think of any more parts to the problem or other use cases I'll send them your way.
because I’m struggling to find the underlying issue filtered through your current understanding of Om Next and the various straws you are grabbing at (which is fully to be expected)
OK, I may just lack a better way of explaining it then. It is the ability to restrict the query graph to the parts that are relevant to the current UI state (or route). Same problem that Google Closure Modules solves for the relevant parts of your JavaScript code, which I've seen you produce great commentary about.
[{route-a-component (om/get-query RouteA)} {route-b-component (om/get-query RouteB)} {route-c-component (om/get-query RouteB)}]
absolutely nothing about Om Next says you have to build your query in this way - the docs just show the expected primary useage.
I want to distribute it to the components for the same value proposition you state for Om.Next. There is a lot of ease and power in the (om/get-query RouteA), which by itself is a nested query graph. The only thing is I just need one of RouteA, RouteB, or RouteC at a given time.
Which is exactly what I suggested I was doing in response to @jdubie and you then stated I was over complicating things and henceforth this conversation.
I think if there is not a more native support of this sort of thing directly in Om.Next, then a router would take the responsibility of filtering the query, as it should know the route.
By aligning routes with query components, i.e. /index.html = :route-component-b, then you could use those keys to filter the query nodes.
@bplatz: we’re not going to add any routing abstraction like that. But also important to not create complications for those who wish to do so.
but based on your earlier statement - which again I don’t fully understand - there seem to be elements that aren’t needed (as far as I tell at the moment)
but you may have determined a reason why this doesn’t work which you haven’t yet stated
I mentioned a route component, yes. I thought there might be other logic required at a nested route node, but I was/am thinking through what would be required for my app.
The component would be a simple reusable part that knew were to insert a nested route inside the dom/component tree, but that part is outside the scope of IQuery
filtering.
Om 1.0.0-alpha15 released, includes some tweaks you can tire kick :shared
and :shared-fn
now
@dnolen: no reason yet that it will not work, that is the path I'm headed down and I'll say something if I run into an obstacle.
for this use case where the root wants to control the query it may be interesting to actually diff the query itself
When considering a typical navigation structure, most of the differentiation happens near the root (your main nav). It is possible limiting the scope to just that is "enough" to reduce the query down, as opposed to having to be precise all the way down to the furthest leaf.
@dnolen: talking about perf, do you think Om.next is suitable for apps with constant animations (like Musicoacher)?
cool, thanks for info
@iwillig yeah @jannis has already demonstrated how easy it is test components in isolation
would like to get devcards history control hooked up here as well as better way to visualize the state
but this is already a much better development / testing setup than I ever had in the past
@dnolen: I just pulled master and tried lein cljsbuild once dev
. It fails with this error: Exception in thread "main" java.lang.AbstractMethodError: cljsbuild.compiler.SourcePaths._find_sources(Ljava/lang/Object;)Ljava/lang/Object;, compiling:(/tmp/form-init38129677347927342.clj:1:71)
I've bumped that to 1.1.1-SNAPSHOT
and now I get java.lang.AssertionError: No ns form found in /home/jannis/oss/om/src/main/deps.cljs
. What version of lein-cljsbuild. Probably still missing something at my end.
Did that with git clean -xdf
before running lein cljsbuild once dev
. I'll paste the backtrace somewhere.
Ah. Running lein cljsbuild
isn't even needed to run the devcards. scripts/figwheel.clj
is what I was looking for.
@dnolen @jannis that is https://github.com/omcljs/om/issues/449 in action
deps.cljs
must be at a source root, it will otherwise be interpreted as a normal cljs ns
project.clj
looks a bit outdated. It still refers to "src/dev"
. And perhaps deps.cljs
can go away and be replaced by an {:externs [...]}
compiler option in the "dev" build.
it probably contains /home/jannis/oss/om/src
when it should contains /home/jannis/oss/om/src/main
@thheller: No, the cljsbuild build contains {:source-paths ["src/main" "src/dev"]}
: https://github.com/omcljs/om/blob/master/project.clj#L30
FWIW, I was receiving a ICollection protocol error on alpha 15/16 and narrowed it down to me using the stubbed out :shared with an atom prior to you adding enhanced support for it. I bring it up because the stack trace doesn't do much to help isolate it the issue. An assertion for map? on whatever is put into :shared would have helped me, although with the enhanced support I would not have put an atom in there to begin with.
@bplatz: here is an implementation of what you described. a) union query in the “routing” component and b) parse-time filtering of the query based on current route. a) https://github.com/jdubie/om-next-router-example/blob/master/src/om_router/core.cljs#L111-L130 b) https://github.com/jdubie/om-next-router-example/blob/master/src/om_router/core.cljs#L43-L47
@dnolen the problem is probably that there are some build targets still specifying :source-paths ["src" "test"]
which is incorrect
@dnolen: It builds after making this change on top of alpha17: https://gist.github.com/Jannis/307e03a461e9b7cc26e3
@dnolen: It doesn't? There is no src/dev
in the repo anymore, so lein cljsbuild once dev
will fail, not finding it. I guess lein cljsbuild
doesn't know about jar-exclusions
?
Ah. Yes, I am. They are still mentioned in README.md so I supposed they are expected to work. But then again, the dev
task is really not that interesting. The examples still build fine.
Hi all, I have an app running with om next which works nicely without any optimizations. However when I stick in :optimizations :simple I get an error for one particular user interaction which says "Assert failed: (reconciler? reconciler)". Does this scream out user error? If so is there anything in particular I should be watching out for?
@jannis yeah that won’t work you should read over @bhauman and I’s thread from a day ago in #C03S1L9DN
@jannis if you have questions you should ask @bhauman I think he understands the issues pretty well
@dnolen: I skimmed through it yesterday or so. I thought one of the issues was the absence of a "history hook". I don't fully understand why but the above snippet seems to make that work. It probably swap!
s the state returned by (om/app-state ...)
and when defcard
then rerenders the RootView
(it calls the anonymous function whenever the card state changes), the reconciler has that state set. Not the cleanest way I'm sure but it seems to work.
Hmm, ok. Both tutorial examples work with the above trick, including history, so I thought that could be the solution. Probably not then 😕
@dnolen, ok now this is under 150 lines, maybe enough short? https://gist.github.com/leontalbot/1d57bb05c063a989757c
the mutation does change the state, but the view doesn't update 😞
@steveb8n Thanks! in the updated link, I do the transact at the second level now. Still the view doesn't update 😕
@leontalbot: Move the :poll/questions
out of the ()
in the transact!
call.
[(selections/update-radio {:name ~id :value ~value}) :poll/questions]
is what you want to pass in.
@jannis You did it!!
thanks a lot!
any other advices?
@leontalbot: Just minor things about coding style. Like: no need for apply
in (apply dom/div nil (map question questions))
and perhaps (for [x a] ...)
would be more readable than (map (fn [...] ...) a)
in render
of Question
, could use more descriptive identifiers for answers than 1, 2, 3, 4, 5 (e.g. :not-interested
, :yes-please
) but the Om side of things look good to me.
Thank you @jannis !
@jannis: be careful about dropping apply with lazy seqs...works in dev mode, not in production
anyone know if repeated browser requests for favicon.ico and om rerenders might at all be related?
@jannis using the minified version of React causes different behavior in regard to lazy-seqs, some binding
s om.next uses will be incorrect which may cause errors
I haven’t seen that in the any of the examples that I wrote with React with advanced optimization on
just got to be careful with it is lazy, due to different behavior in react.js
and react.min.js
that is due to react.js
verifying the children
immediately (thus forcing the lazy seq) ... and react.min.js
not doing this and thus forcing the lazy-seq outside render
I threw away the repo where I verified this ... but you can verify that yourself if you feel like it
not quite, but it did make me look into what React supports which I never actually every used or understood
@thheller: apologize for being so argumentative. It’s a bit frustrating that React doesn’t state clearly anywhere how it’s supposed to work
in Om Next I’ve definitely stayed far away from implementation details this time around
anyways .. if you implement something that forced lazy-seq remember to not throw away microseconds
@thheller: inadvertently you forced feature enhancement since I never knew it was supposed to work this way
and remember this ALWAYS works with react.js
since that already forces all children for you
Really, react.min.js
behaves differently from react.js
? I thought minifying was about syntax, stripping unused stuff but not changing behavior? Ugh.
@jannis no the dev version of react does a lot of validations to warn you about errors
@thheller: Well, that's one thing. It's another not to iterate over lazy sequences to collect everything in one version but not do it another, even if that is just a side-effect of stripping validations. Boo. Well, if we can fix that in Om that would be awesome.
well, React doesn't know what "lazy" means .. so you can't really fault them for that
FWIW I wrote a macro in my stuff for for
(eg. (dom/for [it [1 2 3]] ...)
) that is just a normal for wrapped in (doall ...)
but I only use that for
so it works for me ... doesn't work so well if you use map
as well
no, he is probably working on it right now. need to adjust om.dom
as well and make it recursive
oh, I see. Yeah, I was just reading the factory/force-children stuff, but yeah I missed the om.dom comment
a modification of a minimal example to get om-next rendering server side: https://github.com/thos37/om-server-rendering
#(cond-> % (seq? %) force-children)
(dom/div)
fails (seq? %)
and won't recur ... but adressed if you add it to all om.dom
if say something like react-material-ui is a child of an om component, that won't force anything
they might, but I’m just less concerned because the problems are much bigger than lazy sequences