This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-03-23
Channels
- # admin-announcements (6)
- # aleph (3)
- # beginners (38)
- # boot (119)
- # braid-chat (15)
- # braveandtrue (1)
- # clara (4)
- # cljs-dev (56)
- # cljsfiddle (12)
- # cljsjs (15)
- # cljsrn (6)
- # clojars (4)
- # clojure (113)
- # clojure-art (1)
- # clojure-berlin (1)
- # clojure-dusseldorf (3)
- # clojure-india (15)
- # clojure-new-zealand (3)
- # clojure-poland (1)
- # clojure-russia (83)
- # clojure-uk (18)
- # clojurescript (97)
- # community-development (9)
- # cursive (1)
- # data-science (1)
- # datomic (12)
- # emacs (14)
- # hoplon (350)
- # immutant (2)
- # jobs (2)
- # jobs-discuss (23)
- # keechma (74)
- # liberator (1)
- # off-topic (1)
- # om (127)
- # onyx (54)
- # parinfer (74)
- # pedestal (1)
- # proton (5)
- # re-frame (6)
- # reagent (4)
- # remote-jobs (17)
- # ring-swagger (1)
- # slack-help (5)
- # untangled (16)
- # yada (21)
well I guess I should explain what it is I am doing
I want to make a component that can manage a web socket connection for me
that means that all you need to do is give the component some props (url, and a core async channel) and in the componentWillMount section of the component I set everything up and in componentWillUnmount I tear everything down
then there is a go loop that waits for messages on that channel, uses transit to encode the message and sends it over the web socket
and finally when the server responds the component will add a new transaction with a payload that is the response from the server, and automatically decodes the transit message
that way you don’t need to worry about setting up or maintaining a web socket connection. if you just drop this component into the render function its all taken care of for you
@adamkowalski: you don't need to call a transaction
just call om/merge!
then you don't need a specific parser to be in place
I thought about that, but I ended up making it so as a prop you also pass in a name for the transaction
then when the transaction will occur it will transact under the specified name with the decoded message as the payload
but I don’t want to force somebody to do something specific with the response of the server. maybe they will mutate something, or maybe call another transaction, or maybe nothing at all
I'm not sure that's the way to go about it
well maybe I am going about this the wrong way
but Ideally what I would have are completely isolated components that you can just include into your project and not have to worry about how they work
that way I can start to build up a catalog of reusable components I can share between projects
that's why I'm saying you want to decouple that from a parser
if I use the om/merge! function that would assume that the server is always returning something you want to put into your atom app state right?
or am I misunderstanding what that function does
I suppose, yes
well, don’t most projects define a mutate multimethod that dispatches on the key?
so that way I could just say that a requirement is to add a (defmethod mutate ‘name-your-provided-to-props [{state :state} _ {message :message}] ;; do something )
and that way I can just make a transaction and have the user of the component figure out how to deal with responses
(defn alert
[data owner]
(reify
om/IInitState
(init-state
[_]
{:open? false})
om/IRenderState
(render-state
[_ {:keys [open?]}]
(when (om/get-state owner :open?)
(dom/div #js {:className "alert alert-info alert-bar"}
(dom/span #js {} "message"))))))
@wei: sorry can't answer as that's Om Previous code. If it was Om Next - then you change app state with mutations by calling transact!
, or possibly merge!
.
My question. Here this is how you create the component: (def thing (om/factory Thing))
, where Thing
is a defui
. Was that last sentence correct? Then how come (om/component? (thing))
is returning false?
Perhaps because I'm not giving it props? - no - giving it props doesn't help me. Next thought - maybe it needs to be mounted?
om/component? would return true if it was called inside of a defui component
(defui MyComponent Object (render [this] (.log js/console (om/component? this))))
care to elaborate
I've got a component which I want to be local state only, and am creating it the way normally created, from the parent. In the parent is where the button is that will add local state to this component. So I'm doing update-state
from the parent, but in that call it says it is not a component, hence my question...
Doing this from the parent: (om/update-state! some-component update :squares conj (random-square))
But as you say it won't work. If I turn the two components into one I should be okay - there's no reason I can't do that, so will proceed that way.
another thing you could try is to use a core async channel
I have started to use them a lot for communication between different parts of the system
inside of the inner component have a go loop which takes messages of the channel and mutates the state
the inner component can have the channel passed to it through props
then the outer component can just do a put! channel message
either that, or I think you could use om computed to pass a callback down and that way you could get a reference to the this that you need
I do use them for stuff that's away from Om Next. Kind of loathe to use them for communication between components. I could pass the function down to the child using computed
.
@adamkowalski: A few ways around it - hmm - I think your channel idea may be the only one that will work for this situation. I wasn't able to put the two components together as one is the D3 thing from Tony Kay's Untangled tutorial.
before switching an existing codebase to Om Next, I was ask. Will there be another Om Next? and will the changes be so radical?
@urbanslug: I think that ON is less likely to have flaws than Om Previous. Like say with closing over state using cursors. So the future changes won't need to be so radical. (I just picked that up from listening to talks, never used Om Previous). ON is more of a well though out integrated whole concept type of thing 😜
@dnolen: wrt. the advanced compilation stuff in protocol methods, it seems to me like a CLJS bug. However, the changes in PR #662 make the problem go away for now
I've put together a gist that I linked to in #C03S1L9DN with a minimal repro
@anmonteiro: mind opening a minor ClojureScript JIRA ticket so we don’t lose track of it?
@dnolen: will do, I'll also put the minimal case inline
@dnolen: one more thing, I think I forgot to add support to lists in path-meta
I think this is desirable, don't you think?
should be a simple change
thanks
@dnolen: not a priority at all, but whenever you update Om's pom.xml
I'd appreciate it if you could also update project.clj
with the deps you end up using
@anmonteiro: good pint
I'm implementing a table component with an :order-by param. The render function shows the order-by param and changes it based on a user click event. Suppose the component query (simplified) is [({:data [:field1 :field2] {:order-by ?order-by}})]
, ?order-by is either :filed1 or :filed2. The problem that I'm having is that, if the order-by param changes let's say from :field1 to :field2 but the result of the query is the same (only one item for instance) this won't cause a re-render, and I'm unable to display the correct order by to the user.
@henriqueqc: sounds like a case for custom shouldComponentUpdate
implementation
I'll look into it.
One solution that I came up was to add the param order-by
to the query (and to the app state). In this case, on the click event, I update the params and transact a new value for order by thus changing the query result and causing a re-render.
But this causes another problem, if I want a default :order-by, I have to add it to both the params and the initial app state.
@anmonteiro: Returning true always, works because a render is scheduled after the the set-query! call. But I haven't found a way to compare the params to "next-params" as they are not present in either the nextProps or nextState.
@henriqueqc: there's a hack you can use, but it might change sooner or later
@anmonteiro: I'll keep it like that for the time being. Thanks!
As I understand right now from om-next there are at least 3 places to keep state, at the global atom, as a component local state or in the query using params. If I wanted to keep the order-by
param in the global state atom, how could I keep it in sync with the query params? Looking at the @reconciler
, om already saves the queries under the :om.next/queries
key. Can I read/transact to that key from other components? Is this a thing?
@henriqueqc: Just from listening in here my understanding is that :om.next/queries
will not always be in kept in app state.
@henriqueqc: I wouldn't count on it, I think @anmonteiro is trying to move queries
out of the app-state.
That's a good thing though (I think): keeping certain crucial things opaque isn't a bad thing
@cjmurphy: @iwankaramazow Thanks for the info.
@henriqueqc: aren't query params the right fit for your problem?
@iwankaramazow: I may be misunderstanding something, or using params the wrong way, but as it seems, when you have a piece of state as a query param, you are locked in the ui-tree only child components will be able to access/change the params via parent provided callbacks.
@henriqueqc: you could always put a marker in your app-state :params-for-some-component
, pass those down, and based on those do a set-query!
or update-query!
which updates the components params
You read the thinking in Links tutorial?
Gives you some ideas to escape the ui-tree prison
@iwankaramazow: I've implemented something like that, but it ends up convoluted. Say you want to have a initial value for the query-param, now you have to add it to both the IQueryParams and the initial app-state because on the initial load the param will come from the IQueryParams and after that it will come from the app-state. If your transact function does not depend on the previous value you could get away with just adding it to the IQueryParams. Am I missing something?
@henriqueqc: you know there is (om.next/get-params component)
?
Try sticking to IQueryParams as much as possible
I'm having to create a bunch of similar reads, such as: (defmethod read :language [{:keys [state ast] :as env} k {:keys [query]}] {:value (get @state k)}) (defmethod read :repository_full_name [{:keys [state ast] :as env} k {:keys [query]}] {:value (get @state k)}) How to refactor them in something that can be shared?
@thiagofm: if there's only a common case, the simplest way would be to put them under the :default
key
@thiagofm: You don't have to use multimethods. In some of the tutorials there's one read method and a case statement.
Okay, but if I use only one read(and a couple of different queries), would Om next still know when it should rerender something because a query changed? (Just a guess, probably not true)
@thiagofm: multi methods or a case statement isn't conceptually different for the reconciler
Reads are how ON gets to fill in the data for keys. It doesn't really matter how you implement the read. One thing you could try is putting println
statements in the :default case, just to see what ON asks for.
@thiagofm: you should look into making a default read function which can just be (defmethod read :default [{state :state} key _] {:value (get @state key)})
and only if you have a read which is doing something non trivial should you make a new method for that edge case
@adamkowalski: but then how would I specify it in the IQuery?
no, it will happen if no multimethod is defined for that key
which is exactly what you want
https://github.com/omcljs/om/wiki/Quick-Start-(om.next)#changing-queries-over-time
here david shows how you can have a default read method as well as a specialized one
What I would do is have (defmulti read om/dispatch) so that way you dispatch on key then (defmethod read :default) like i showed above
I just mistakenly posted in #C03RZGPG1, so I'm reposting my newbie questions here now.
What is the second argument to db->tree
? I understand one wants to run a query against the database and get denormalized results, but what's the second argument and why is it usually the same as just the database again?
Is there a list of db->tree
usage examples somewhere?
@francoiswirion: you can check Om's tests
@anmonteiro: thanks, will check them out. I see the api documentation of db->tree
is a bit sparse. Is there appetite for having examples in the documentation? I could contribute some explanations if and when I figure this out.
anyone have insight into this error message?
core.cljs:264 Uncaught Error: No protocol method ICollection.-conj defined for type cljs.core/Keyword: :font-lock-comment-delimiter-face
It showed up as soon as I changed a components query from [:code-face]
to [{:code-face (om/get-query Face)}]
I think I either found a bug, or I am doing something wrong(probably?). I have in my root component: [{:repository (om/get-query code/Code)} {:code (om/get-query code/Code)} (nth (om/get-query code/Code) 2) (nth (om/get-query code/Code) 3)]) In my children: ['(:repository {:query ?language}) '(:code {:language ?language :repository-full-name ?repository-full-name}) '(:language) '(:repository-full-name)] For some reason, only the first query, :repository get the params(such as ?language). The second query in order doesn't get the params. If I do a get-query, I see the params there, but when I am in a reader, the params aren't there, they are the default value(nil, in my case).
I've tried exchanging order between repository and code queries, and still the same thing happen. Code get both of its params, and repository gets none.
thiagofm: you can’t do (nth ..) (first ..) etc on a query to change it, the metadata gets messed up
how do I specify it instead? I'm not having problems with this part of the query though
specify the root query? it should be a combination of the queries for children
if the root needs some of the same data as Code, then you probably want an ident for that data
Root doesn't need anything, I just have to specify it there because otherwise things won't work
All that I've wanted was, in my children, to query: ['(:repository {:query ?language}) '(:code {:language ?language :repository-full-name ?repository-full-name}) '(:language) '(:repository-full-name)]
hmm, i’m not sure the query language works with ‘(:language).. if you want :language without params just specify :language (no list wrapping)
that could be the issue
which for some reason, the first one gets ?language, but the second doesn't get ?language and ?repository-full-name in the reader. If i swap their places, the first one gets it and the other doesn't
@seanirby: mind providing the full stack trace?
Example get-query: [(:repository {:query "ruby"}) (:code {:language "ruby", :repository-full-name "rails/rails"}) (:language) (:repository-full-name)] (everything in place, perfectly!) Example output(ast, inside the reader) -- All query related things are nil: {:type :join, :dispatch-key :code, :key :code, :query [(:repository {:query nil}) (:code {:language nil, :repository-full-name nil}) (:language) (:repository-full-name)], :component haxlife.components.code/Code, :children [{:type :prop, :dispatch-key :repository, :key :repository, :params {:query nil}} {:type :prop, :dispatch-key :code, :key :code, :params {:language nil, :repository-full-name nil}} {:type :prop, :dispatch-key :language, :key :language, :params {}} {:type :prop, :dispatch-key :repository-full-name, :key :repository-full-name, :params {}}]}