This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-01-20
Channels
- # aatree (42)
- # admin-announcements (25)
- # alda (28)
- # aws (56)
- # beginners (67)
- # boot (248)
- # braid-chat (9)
- # cider (52)
- # cljsrn (11)
- # clojars (4)
- # clojure (341)
- # clojure-czech (5)
- # clojure-japan (3)
- # clojure-nl (2)
- # clojure-russia (57)
- # clojured (10)
- # clojurescript (35)
- # community-development (18)
- # cursive (17)
- # datascript (5)
- # datomic (39)
- # dirac (25)
- # editors (2)
- # events (3)
- # hoplon (60)
- # jobs (5)
- # ldnclj (9)
- # leiningen (5)
- # mount (20)
- # off-topic (3)
- # om (263)
- # onyx (69)
- # perun (5)
- # proton (55)
- # re-frame (7)
- # reagent (24)
- # spacemacs (6)
- # yada (16)
My callback receives data from remote read, but components aren't updated after that https://github.com/andrewboltachev/html2om/blob/master/src/cljs/html2om/core.cljs#L118 What can cause this?
UPD: figured out that neither props contain :om-text/om-text
nor render
is called on cb
launch
@andrewboltachev: I think the issue is that your read
fn for :om-text/om-text
will never return a :value
. Your components only ever get data from your parser, so you need the read
fn to return the local :om-text/om-text
data from your apps app-state.
@noonian: yep I were looking at "autocomplete" example from devcards (this one uses custom remote also), and it were providing :value
for remote read also.
Yeah, you probably want to only return a remote if the local value isn’t already in the state
such "memoization" is cool, but say I want it to call the server in any case — would I need :value
then also?
and, how would it work then? i.e. when I return {:value "" :remote true}
would the value be first set to empty string and then to the fetchd one or what?
Not sure, but I think you need to be careful of an infinite cycle of remote requests. I haven’t played with om.next for a bit, but I think after you remote callback happens, the data gets merged to the app state and then your parser will get called again to re-render the component. If the parser always returns a remote that basically means always hit the server so it could keep making requests.
something like this is probably where I’d start:
(defmethod readf :om-text/om-text
[{:keys [state] :as env} k params]
(let [st @state
local-val (:om-text/om-text st)]
(if local-val
{:value local-val}
{:remote true})))
btw "autocomplete" deals also with ast
parameter https://github.com/omcljs/om/blob/master/src/devcards/om/devcards/autocomplete.cljs#L34
not sure what it is, but e.g. for me it's {:type :prop, :dispatch-key :om-text/om-text, :key :om-text/om-text, :params {:html {:value safdsfsfd}}}
Yeah, I think :remote true
is syntax for returning :remote ast
where ast
is the value from the parser environment.
but if you return the ast, you can tweak the ast node yourself so the remote query is not exactly what the local query is
so, may be
btw, one branch in your code is original to mine, i.e. just {:remote true}
because it only returns {:remote true}
if the local data isn’t there, in my version it will only send 1 request to the server
and... would UIs that implement IQuery
with (:om-text/om-text {:html ?html})
be updated then?
I mean would render
be called
I think after you return {:remote true}
, then your server will return the data and it will get merged into the app state. At that point, your parser will be called with the query for your component and your component’s render function will be called with any local data returned from the parser
Thanks for great help @noonian !
I did try this autocomplete now
it doesn't work on my versions of stuff
Just make sure at some point you return a :value
for all of your query keys. Otherwise, you components wont get that data.
though, works... (seemed like not at first)
@noonian: FYI fixed. And the way it works is a bit unclear for me. See I had to return the map with both keys: https://github.com/andrewboltachev/html2om/blob/master/src/cljs/html2om/core.cljs#L88
last night I integrated local storage persistence for one component with an om.next remote! so good
humm... well crap.. having an om app in figwheel mode crashes the Samsung Smart TV Tizen browser 😞 Not sure how to debug, as there is no way of checking logs remote. I did a hack by redirecting console.log to a <div> but no luck catching any javascript errors. Might be some relevant log happens at the time of the crash, but then the browser is gone so can't see that. Via wireshark (tried loading the app content directly from my laptop via an iframe) I've seen that it reaches the loading of transit writer. I'm not using transit, but my attempts to simply comment out any transit loads didn't help (the idea being either OOM or that transit writer somehow triggers some bug in the browser). A production build works just fine though. Is it possible to do partial minification and still have figwheel? Any suggestions?
@dottedmag: The emulator made me cry so I gave it up and developed the app in chrome instead but now it's time to start using the device specific apis so no escape any longer. But good point. Should try it out.
Hopefully it's reproducible in the emulator and it can give me more details on what happens.
@dnolen: User-Agent: Mozilla/5.0 (SMART-TV; Linux; Tizen 2.3) AppleWebkit/538.1 (KHTML, like Gecko) SamsungBrowser/1.0 TV Safari/538.1 Accept-Charset: iso-8859-1, utf-8, utf-16, *;q=0.1
you may need to modify your dev builds with :static-fns true
compiler option to avoid issues
Excellent, now it starts at least, doesn't connect to figwheel websocket though. But that's hopefully easier to figure out why.
wow that's great.
Where are you on the reloading issue?
Keeping state? Haven't looked any more at that. Moved on to get the figwheel setup running on the TV instead. It would be nice if state was kept, but my navigation depth in the app is only 3 steps so it's not that much of an inconvenience. Not sure if you saw but I think it's the static IQuery that messes up. My routing details in the app-state are correct after the reload, but the component seems to get its original query on reload.
@nano: right, that makes sense because defui
will just overwrite those functions on reload
but that makes sense, IMO, if you change those functions you want them to be changed on reload
@nano: you can't have both
Yep, would be fine with not being able to reload the root component's query without a full reload of the page as that's not something that will change much.
as long as the class doesn’t change on reload you should be able to preserve component local state
queries are stored in the app state atom - so you’ll want to protect that too with defonce
@dnolen: I've expressed this concern previously, and please correct me if I'm wrong. I think that all defui ^:once
does is preventing a new class to be instantiated (by not calling its constructor). However, from the experiments I've done with reloading, the class's prototype is patched and then add-root!
mounts this new (changed) class, which doesn't keep component local state
@anmonteiro: that’s not how React works
right, I know they don't create a new instance
but somehow I wasn't able to get compnent local state to be maintained
and I'm not sure what I've missed then
cool to know that, I didn't
in anycase, it should work - but it may be that there’s a bug that prevents it from working
@dnolen: right, so I'll try again and report back with a minimal case
if I'm able to find one
@dnolen: I'm definitely seeing the constructor getting called on reload
GH issue?
@anmonteiro: like I said that’s not how React works
oh that's not what I understood
well, then, if defui
contains this: (set! (.-state this#) (.initLocalState this#)))
then local state will never be maintained...
so there's a bug; I just was expecting React not to call the constructor everytime
should be an easy fix, do you want to work on it or should I?
@anmonteiro: PR welcome
great
@dnolen: My query changes after I reload, even with (defui ^:once on all components, and (defonce app-state (atom ....)). I'm doing routing via queries, but the om/IQuery func declares a default route, [:session/route :session/params {:child (route->query :categories)}], and this is the query I get after performing a change and figwheel reloads.
the issue is very low priority for me - but I’m happy to take a PR provided you submit a CA
making progress on the error stuff again, so hopefully won’t be too long before I can help out on these lower priority issues myself.
the only time that :dispatch-key
and :key
are different in the query AST is with an entity reference (ident), right?
Looks like it: https://github.com/omcljs/om/blob/master/src/main/om/next/impl/parser.cljc#L103 vs. https://github.com/omcljs/om/blob/master/src/main/om/next/impl/parser.cljc#L46
@jannis: I got a basic app working that runs queries on the backend against a sqlite db! this is going to be awesome (needs some more fleshing out before it's actually practical)
right now all I do is convert a join query into a SELECT statement which is straight-forward, not sure what else I will need yet
the straight-forward-ness of the API is what made me try it (relay/falcor look way more complicated). plus, I've been meaning to actually use CLJS on a project
@dnolen: regarding the local state reload issue, not finding it straightforward to know where to set!
the state; if the constructor is called everytime and we don't set it there then the component state will be null
@anmonteiro: maybe you should see if mounted?
works in the constructor
it maybe also be the case that we need to set state when the component mounts before user code
@jlongster: that’s cool that you have a sqlite thing going
@dnolen: OK thanks for pointing me in some new direction; will check that out
@anmonteiro: it might be a little bit fiddly but that’s OK
@dnolen: yep, I've been looking at some React source to try and see if there are any extension points related to this bit
@dnolen: definitely going to blog once I feel more comfortable with this! it's very basic but I'm eager to get filtering and other queries working. should be pretty neat.
it seems that if we were using React.createClass
it would be easier
@anmonteiro: related, I’d completely forget that static prop
is a thing
didn't know about that
@anmonteiro: would need to set it on the prototype I think
OK let's see what I come up with given these new bits of info
I would try the property direction last since we need to special case it in the defui
macro
@jlongster: cool!
@dnolen: right. I would also be more comfortable going in a way other than that
gotta run now, I'll play with all this later
Is there a way to get child components? I know there's a children function, but looking at what is actually returned by react, if you examine .-props and .-children, it is null. Also, react-ref, which is -.refs <name> just returns a dom node, not a component. I ask because I was looking into using set-query! and making it work from the root to child components. The root usually uses get-query, but it's grabbing the static query of the components, and not necessarily the instance of the child component's current query--which may have changed during runtime.
@taylor.sando: you can set-query!
from the root, i.e. make your own way for components to set queries if this is necessary
So all parameters that would change would need to be stored at the root, or in the app state?
Om only ships the primitives here, write whatever abstractions and helpers you want/need
I've been trying to get reforms
into my project but I can't seem to have a for start with initial values they actually get erased once I load up the component. Any tips or alternatives to pre-populate a form with reforms
? or should I be using something like formative
?
@dnolen: something I just confirmed which I'm not sure is expected behavior
whenever we reload a file, these methods are triggered in an Om Next component: componentWillMount
and componentDidMount
however, if I use BHauman's defonce-react-class
, the component will trigger componentWillReceiveProps
, componentWillUpdate
and componentDidUpdate
instead
I somehow was expecting that the component would remain mounted, allowing us to set the initial state in e.g. componentWillMount
before user code, as you suggested
it seems that React also uses componentWillMount
for some of their own initialization logic
so atm I'm considering that add-root!
is doing something that causes Om Next components to unmount on reload, and I'll start pursuing this direction
@anmonteiro: I would make sure this isn’t a devcards problem before going on a wild goose chase first
@dnolen: I haven't been using devcards to test all this
all directly on the DOM
so I've found the root cause now
whenever we call add-root!
again (e.g. on reload), remove-root!
unmounts the component.
And I knew this, I was just choosing not to see it
I'm not sure what to do given this information
what do you mean handle that in user code?
uhm, let's see how that pans out
@anmonteiro: it’s easy to do
just did
I’ve been calling add-root!
on each figwheel reload to re-render the app, but I suppose you could achieve the same behavior using the touch!
helper when that lands.
@dnolen: what I did was defonce
the add-root!
call?
@anmonteiro: heh right, that’s the one-liner version
OK but there's a problem
now the component just doesn't update at all on reload 😄
Local state is maintained ofc (yay?) but if I change the render method it doesn't update
until touch!
lands, you can probably pull the root component instance out of the reconciler and call .forceUpdate
on it directly on figwheel reload
@noonian: trying that now
also, not sure touch!
is supposed to be used to do that
depends on the use case, I suppose
@noonian: there's also force-root-render!
which seems more appropriate
Ah, that sounds perfect for this use case. I haven’t been able to play with Om.next very much lately (got a new job) so I didn’t know it existed.
though it doesn't seem to be doing anything
@anmonteiro: pretty sure figwheel has a hook for reloads
it does, yes. Let's see. However (.forceUpdate c)
doesn't seem to update the component when changing the render method
An attempt at a minimal (failing) attempt to use om.next with the React Native Navigator and ListView components. https://github.com/hugoduncan/navigator-repro
@dnolen: so can't get component to update without calling add-root!
again. And if I do so it blows away local state. Doesn't seem like a very good position to be in
@dnolen: I can’t imagine it is a problem outside of React Native. I get the impression that the Navigator and ListView components manage their children in ways that om.next doesn’t expect.
I'm not sure it's a figwheel thing or that I'm doing something wrong; the instance just doesn't get the new render method on reload, I don't know why
@anmonteiro: so you see the old render method get invoked though?
it's calling componentWillUpdate
, render
and componentDidUpdate
(now as expected). the old ones though
could it be a defui
bug? I just don't see where
@anmonteiro: I would test by examining the prototype
@dnolen: I’m guessing the component props don’t have the right omcls$…
values set on them, but I can’t see what the expected code path is in full-query
for a non root component that doesn’t have a class-path match and doesn’t have a path set on it.
@dnolen: before doing that, let me rule out anything I might be doing wrong. How would you make a component update on reload?
@dnolen: I’m wondering if path should be set via ident, and/or why full-query doesn’t use ident
@hugod: your theory doesn’t match anything that might be related to React Native so far
@anmonteiro: forceUpdate
should work
@dnolen: it's how I'm doing it. I've tried that one and force-root-render!
I have a theory though, but might be wrong
@anmonteiro: I’m just talking about inspecting the prototype
I know
the thing is that the instance that's already there wouldn't get the new prototype
I believe this is what happening. we would need to set __proto__
on it, but that's not cross-browser compliant
@anmonteiro: proto__ is a de facto standard at this point
@dnolen: I don't get it. A live instance doesn't have a prototype, AFAIK. so setting the class's prototype would not do anything
@dnolen: well, the components will do things like create components outside of an om render!
call. I guess I could try and implement Navigator and ListView like components outside of ReactNative.
@dnolen: As an example, I push a view onto the navigator, by passing it the factory function, which then gets used by the navigator component to re-render itself.
@jlongster: hah! that works
@hugod so are you are or aren’t you saying the issue is that the dyn vars don’t get propagated correctly with the RN views?
@anmonteiro cool! I think it's the same behavior as setting proto__, just more standards compliant. although Safari doesn't support sPO (according to MDN). if just for dev, should be ok
@jlongster: yep, I went to read it on MDN, they also show a polyfill
@dnolen: I think I am correctly propagating the dynamic var bindings. The list view is not behaving correctly though, so I am trying to understand what else is missing.
@dnolen: I understand completely The code is pretty much taken from next.clj
: https://github.com/hugoduncan/navigator-repro/blob/master/src/navigator_repro/macros.clj#L3
@hugod the macro isn’t useful to me … where are you using that … that’s all that matters
if you haven’t monkey patched the RN render
methods unlikely to make any difference at all
@dnolen: Ah, misunderstood. I’m using it in the ListView https://github.com/hugoduncan/navigator-repro/blob/master/src/navigator_repro/core.cljs#L147 (I used a separate dynamic var to suppress navigator re-rendering https://github.com/hugoduncan/navigator-repro/blob/master/src/navigator_repro/core.cljs#L162)
Alright. So this is working:
(defonce root (atom nil))
(defn init []
(if (nil? @root)
(let [target (js/document.getElementById "app")]
(om/add-root! reconciler RootView target)
(reset! root RootView))
(let [c (om/class->any reconciler RootView)]
(js/Object.setPrototypeOf c (.-prototype @root))
(om/force-root-render! reconciler))))
for reload hooks w/e
@dnolen: my question is: should the prototype patching make its way into Om?
I'd say no, it seems to me that it's only a dev time helper
but you might be thinking of something I'm not
@anmonteiro: if there’s a way that covers most browsers I don’t see the problem
@dnolen: could get away by using MDN's proposed polyfill
which is setting __proto__
if setPrototypeOf
is not available
I just wouldn't know where in Om's code to put it, actually. maybe in force-root-render!
?
mind that we need both access to the class and the instance
force-root-render!
is in the context of the reconciler so it has access to both
@anmonteiro: so the problem may be that we blow away the prototype during relaod
@dnolen: the problem of what?
the mounted instance won't even see that update, IMO
since it's instantiated?
@anmonteiro: prototype lookups are dynamic, it should work
@dnolen: you were right about the defui
macro. that line is problematic.
question: is it OK that we blow the prototype away if ^:once
is not specified?
alright then. patch incoming
that should do it. force-root-render!
now works as expected on reload
thanks for the guidance!
I’m trying to find the devcards based example that someone built showing how to wrap a client parser around a 3rd party api. Does anyone know where that is? Asking for a friend 😉 update: I found it… https://wilkerlucio.github.io/om-cookbook/#!/om_cookbook.Parsing_Service_Databases_as_Remote
@sjol I've used reforms by using the rum integration: https://github.com/aspasia/rum-reforms In the render method, I created a regular atom around the props, added a watcher, passed that to reforms, and inside of the watcher's callback did an Om transact with the updated data. It's not really rum specific, since it just uses an atom instead of a cursor.
Hi guys
I've just finished (though rather "started") "HTML2Om" project, intended to help converting HTML to (dom/div #js {:className ...} ...)
Om syntax.
It's Om Next webapp itself. Please check it out: https://github.com/andrewboltachev/html2om
Feedback and critics would be highly appreciated!