This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-03-08
Channels
- # aws (3)
- # beginners (126)
- # boot (19)
- # cider (31)
- # cljs-dev (324)
- # clojure (96)
- # clojure-boston (2)
- # clojure-denver (9)
- # clojure-dusseldorf (2)
- # clojure-greece (4)
- # clojure-italy (5)
- # clojure-losangeles (1)
- # clojure-spec (18)
- # clojure-uk (59)
- # clojurebridge (1)
- # clojurescript (184)
- # community-development (29)
- # cursive (2)
- # datascript (2)
- # datomic (5)
- # emacs (1)
- # figwheel (6)
- # fulcro (270)
- # hoplon (2)
- # jobs (1)
- # jobs-discuss (1)
- # keyboards (2)
- # leiningen (2)
- # london-clojurians (2)
- # luminus (10)
- # mount (1)
- # off-topic (26)
- # onyx (8)
- # other-languages (1)
- # parinfer (1)
- # protorepl (6)
- # re-frame (23)
- # reagent (61)
- # reitit (5)
- # shadow-cljs (100)
- # spacemacs (3)
- # sql (19)
- # unrepl (90)
- # vim (25)
New 2.3.2-SNAPSHOT on clojars. The new alpha DOM support has been tweaked and tuned. Most combos work properly now.
WITH THE EXCEPTION of input
, select
, option
, and textarea
…those are still pending.
@tony.kay nice! just to confirm, the new css syntax does namespace the classes to the current component?
no…integration with fulcro-css is something we just discussed…going to use symbols for that
so, not working yet, but: (div '.some-class "Hello")
will mean “get the css classname from the binding named some-class
humm, is there a way to use multiple namespaced classes with this model?
ah, true
and then we get both global and localized names, with notation that indicates which is which
fair enough, looks weird, but I think can get used with time
I understand this in the point of flexibility, but I was expecting more integration of fulcro-css there, maybe I'm biased because I always use the fulcro css for styling
but what about using :.class
for namespaced css and :$class
for unnamespaced (like the fulcro css syntax)?
the great thing about this would be not having to destruct from the css, that's a bit of pain I think
but it also makes me want to pull fulcro-css into fulcro proper and not have a separate lib
my first impression is that could be a good thing
@currentoor what are your thoughts?
yeah, in terms of flexibility the current idea seems to win
good thing we can keep that on alpha
for a while and experiment around it
humm, interesting
not sure how the pluggable works without being a pain, though (or hurting RT performance)…a lot of this is being done in macros AND at runtime, depending on the combo
for that matter, THIS dom namespace in fulcro-css perhaps causes your argument to win (though support for syms would still be useful)
that way the old DOM just stays where it is, and if you want the new cooler syntax you use fulcro-css, which is a super-thin lib that you should really be using anyway 🙂
then maybe fulcro-css becomes fulcro-dom, which was another request we had…export the DOM stuff for react as an add-on lib.
cool, I'm hosting some guests now, have to leave the computer, let's talk more later
@currentoor I’m porting a larger app, and there are definitely some problems still with alpha dom. Using fn
macro isn’t happy, for example, for callbacks.
i prefer fulcro-css be part of fulcro proper, i think the value it provides is worth the added complexity, is there any way we could add it by default and opt out if needed? i think we should be doing more to encourage fulcro-css
com.yahoo.platform.yui/yuicompressor
i already checked 😅
pluggable seems nightmare-ish unless we do it all at runtime
if we agree that fulcro-css is a good thing to use in general, perhaps we should embrace that?
only if we bring fulcro-css in, otherwise if we decide to keep things separate then this goes against keeping things separate
how are they affected?
just sayin that there are a lot of ppl in the react community that will see the difference as an annoyance if looking into Fulcro
oh as in they’d rather use sablano with defsc
?
so it would be initially annoying to them (if they have external CSS, like they might) to have to use $ instead of dot
seems like a valid concern now that you mention it, what if we reversed the notation? :.a
is not namespaced but :$a
is namespaced?
or some other character?
which would be a breaking change we don’t want?
so, you say
(defsc Comp [this props]
{:css [[:.a ...]
[:$a ...]]}
(div :$a (p :.a "Hello")))
yes, exactly
i believe that was @wilkerlucio’s point too
So, the problem with kws that use fulcro-css conventions is that the containing class is not known when the elements are being evaluated…it turns it into runtime overhead, and that runtime overhead also involves using a dynamic var….don’t like either of those
the symbols are fully general, work with let expressions and fulcro-css, and don’t incur weird overhead unless you use them…even then you can still do partial evals at compile time
i wonder if fulcro CSS could be modified to better serve this usecase?
like why can’t it expose it’s classes at compile time?
what do you mean?
it sounds like quite a tangle to get the symbol from an outer macro down into the inner macro, transparently
where it would scan the body of the render at compile time and transform the keywords if you set something like :use-css-keywords true
in the options map
so that could turn all the keywords into :$name$name2
something like that?
oh it would do .items-wrapper
to .fulcro-css_cards-ui_ListComponent__items-wrapper
depending on context?
does the outer macro get expanded first?
opposite of functions right?
i was going to suggest defsc
puts the fulcro-css_cards-ui_ListComponen
in a dynamic var that child macros have access to
in a map called *context*
for other things like this
and the child dom macros do their own re-writing (kw literals only allowed)
It seems macros go outside in: the body is unevaluated, then the output is re-evaluated
(defsc ListComponent [this {:keys [id items]} computed {:keys [items-wrapper]}]
{:css [[:.items-wrapper {:background-color "blue"}]]
:css-include [ListItem]}
(dom/div :.items-wrapper
(dom/h2 (str "List " id))
(dom/ul (map ui-list-item items))))
that’s what i was thinking
composition is not good, though, for this solution. If you define some function or macro that contains other code, it won’t be in context for translation
the symbols are just better. They’re a little more boilerplate for destructuring on the first line, but they completely compose…you can pass them along to other functions, etc.
BTW, I punted on inputs, alpha DOM now has them, but they are a non-wrapped variety. Use fulcro.dom
form elements (without the sugar) if you need wrapped for now. I’ll integrate the wrapped into the new syntax in the coming days.
So, @currentoor what do you think? Move forward with symbol support instead of all of this other mess?
(defsc ListComponent [this {:keys [id items]} computed {:keys [items-wrapper]}]
{:css [[:.items-wrapper {:background-color "blue"}]]
:css-include [ListItem]}
(dom/div '.items-wrapper
(dom/h2 (str "List " id))
(dom/ul (map ui-list-item items))))
that still looks pretty good IMO
I think so, too. It isn’t quite as “special”, but the problems with the localized css seem pretty ugly
i’m with you on moving forward with the symbol stuff, but i’ll have to work on it tomorrow
maybe @wilkerlucio can weigh in by then too
Yeah, I really don’t see how to make the keywords work reliably, given all of the execution contexts and composition possibilities. Bugs would be a pain to figure out, and would be mysterious to users.
in the new networking system, when using custom remotes to legacy APIs, is it preferable to make a new record that implements FulcroRemoteI
, or use the existing fulcro-http-remote
, and pass in custom middleware?
@levitanong depends on how much customization you need, if fulcro-http-remote
can handle your needs, go for it
@wilkerlucio AFAIK it’s not meant for use with REST APIs. I’m currently trying to go with the method wherein i just make a record which implements FulcroRemoteI
, but i’m kind of hitting a brick wall with ok-callback
. is there anything else besides {:transaction ... :body ...}
that I have to know about regarding ok-callback
?
@levitanong I think you can use for REST api's as well, if I don't remember wrong @tony.kay was using it like that for some contract project. about the custom impl, I think :transaction and :body are all to know, I had issues when I tried that first because I missed those. What's happening on your case, the callback is not been triggered?
@wilkerlucio the data doesn’t seem to be merged in. When I checked the transaction log, the merge is showing that the :data-tree
has :not-found
as a value in its keys.
merging problems usually happen when there is mismatch of query/data, did you confirmed the data is in the right shape?
as far as i can tell, yes. Especially since i was previously using FulcroNetwork
, and it was working
if I remove :transaction
, should it still merge into state, just skipping the normalization step?
also, perhaps this will be relevant: I’m using df/load
I don't know that much about the new internals, what I can tell you is that the old one is not likely to go away, so you can still use that
I can't debug with you now, I have to leave, but we can talk more later, or Tony can probably have a better idea on what might be going on, sorry can't help you more now
thanks for your time, @wilkerlucio.
It does seem the old system will disappear though, as it’s been labelled as deprecated
.
have a great day! 🙂
thanks! same to you 🙂
it just means new stuff should try to use the new one, but we try to follow the "don't break things" rule as much as possible 🙂
good to know! thanks again.
@levitanong read the source of the implementation if you're going to implement your own. There are two models I'd recommend for REST: if you only ever need one network request per query, then middleware. If multiple, then wrap the new http implementation, don't go all the way to low level. The implementation doesn't care what is in the request. No reason at all to implement xhrio behavior at all
@tony.kay what do you mean by wrapping the new http implementation?
Be careful that you understand the current middleware. The response middleware in particular for your case
oh interesting
you mean to say i instantiate a FulcroHTTPRemote
, and call those methods from within some outer record that implements FulcroRemoteI
?
I was actually considering to also make a request middleware to change the url/query-params, etc…
relevant to the query
right. So, the normal response middleware just rewrites the (plain text) body from transit:
https://github.com/fulcrologic/fulcro/blob/develop/src/main/fulcro/client/network.cljc#L158
Here are where the handlers are defined internally: https://github.com/fulcrologic/fulcro/blob/develop/src/main/fulcro/client/impl/application.cljc#L55
Yeah, I’ve tried this, but somehow things aren’t working. 😅
do you know if there are any gotchas when using df/load
?
i’ve commented all but one to isolate that possibility
The loaded callback that becomes done is a wrapped form of this: https://github.com/fulcrologic/fulcro/blob/develop/src/main/fulcro/client/impl/data_fetch.cljc#L497
i’ve also made the class argument of df/load
nil to avoid normalization
(in which case I’d assume the transaction
key would not be necessary
I see
yes, i’ve seen this as well
I’ll make a minimal case and see what happens 😄
for a load, you have the burden of making it match, actually….let me think about that
some lost metadata?
but if i’m not using normalization, the metadata wouldn’t matter though, right?
take your time 🙂
So, for any given sequence where you’ve queued loads (you held the thread, issues more than one load):
1. Those loads are combined into a single query 2. The individual loads are remembered, and the data fetch “loaded-callback” is called with the load items, because each could have fallbacks, post mutations, targeting, etc. 3. So, the transaction for loads is ignored
and the remote code must examine the transaction to see what all is combined. You’ll end up writing a parser at the network layer, typically, to process the query and figure out what all you need.
At the networking layer you could leverage core.async
and such for coordination among the different REST calls you might make…and yes, middleware on the lower level remote would let you easily set things like headers and method.
hang on. you mean to say that for loads, i should pass the novelty naked instead of wrapped with {:transaction ... :body novelty}
to the ok-handler?
it’ll take some time for me to digest this i think
https://github.com/fulcrologic/fulcro/blob/develop/src/main/fulcro/client/impl/application.cljc#L188
you can see that the load items are the thing of interest, so it closes over them, and only uses the first arg. The first arg at this layer is the body
re: core.async
, you mean i should use go
to wait for both network requests to complete before passing them on to ok
?
i remember running into this before, and worked around it by setting :parallel
to true
😛
yeah, so if i use parallel, the multiple calls to df/load
end up as single individual queries
that is what releases the load queue. If you use parallel, Fulcro doesn’t use a queue and doesn’t care.
i see
but yes, you have to manage that at the networking level. The model doesn’t get rid of the fact that js is async…just isolates it to the lowest layer as much as possible
So, perhaps it would help to trace through a load for you: 1. You issue one or more loads (they go into a storage queue, not an async one) 2. The remoting layer is triggered, and pulls as many load items as it can from the storage queue 3. As many of those that are compatible (don’t share the same dispatch key) are turned into a single query 4. A callback handler is generated to handle the result. That callback handler is given the list of load items that must be processed. 5. The application layer creates ANOTHER callback that can call (4) with the result (body), but only the result. 6. The resulting callback and combined query is placed onto an async queue for the remote in question 7. An infinite go loop pulls things from the async queue. It wraps OK and ERROR with code that will put something into a core.async response queue, and calls that remote with it, then waits by doing a take on the response queue 8. The callback in (7) is what you see at the network layer. When you call it, it releases the go loop, and passes the data through the chain…like a middleware chain
ok, so i understand
but as I understand it, there shouldn’t be much of a problem if i only issue one unnormalized load for a remote (say at startup)
and calling (ok-handler {:transact [:foo] :body {:foo :bar}})
Be sure you log what you get. It should look like this: https://github.com/fulcrologic/fulcro/blob/develop/src/main/fulcro/client/impl/application.cljc#L58
yeah, that’s definitely above board.
the odd thing is i’m getting a {:foo :fulcro.something.something/not-found}
in my state.
ok so now i know what the expected behavior is, I can work towards building a minimal case to hopefully either find a bug, or find a problem with what i’m doing. 😛
i’ll get back to you soon! thanks for your time, @tony.kay!
wilker mentioned that one usually gets that through faulty normalization
mismatch of the query (incoming EDN in the case of a load) and the response you give
The whole power of the entire Fulcro story for this is that you send a graph query, and get a normalized result in your database. That is done by tree->db
, which uses the query and tree of data
if they don’t match, then the query is asking for something that isn’t found in the response
If I tell it “OK” with EDN of [:x]
and give it {:x 1 :y 2}
the :y
stuff is thrown away
as far as Fulcro is concerned, the network layer gave it stuff no one asked for…i.e. the low layer did a poor job and over-queried.
If there is no query for a bit of data, there can be no conversion of that data into the database. It is “unsafe”…the user didn’t ask for y
and would be surprised if it did something like overwrote an important value they cared about. It would be mysterious
So, the low layers of load are not allowed to “override” what the user expects from an explicit load query
You have to be in the “lower abstraction layer” mindset when working at the network layer here. The higher level abstraction is “the user asked for :x
“.
Of course, from that argument, one could say that allowing the middleware access to the tx for mutations breaks that abstraction a bit, which is true. But with a mutation, though, there can be the idea that some result from the server should cause some arbitrary change to your database.
@wilkerlucio in case you haven't seen it, I made a PR to pathom
btw, walkable should work well with placeholders now
@myguidingstar nice, glad to hear, I got the notification, just didn't had the time to stop and do a proper code review, I expect to check on it before next week 😉
@tony.kay @currentoor just read the discussion from yesterday, seems like you guys went though a mess of macros 😛, seems like the full integration is a pain, the symbol solution sounds like something nice, but having to destructure feels like more work than the current impl, right now what I do is something like this:
(defsc SomeClass [this props _ css]
{:css [[:some-class {:color "#000"}]]}
(dom/div #js {:className (:some-class css)}
"bla"))
I just had a though, what if we use some custom reader with a custom attribute, let me write an example of what I'm thinking
vs.
(defsc SomeClass [this props _ {:keys [some-class]}]
{:css [[:some-class {:color "#000"}]]}
(dom/div '.some-class "bla"))
what I don't like about that is the repetition, I have to write same class name at least twice for every usage
yeah, but you’re not saying :className
over and over. And it isn’t repitition in the non-DRY sense…it’s just a compact definition, lookup, and use.
on the format I wrote I can have snippets that write the boilerplate for me, but I can't have a snippet that knows about how to add destructuing on defsc
@tony.kay what about this:
(defsc SomeClass [this props _ css]
{:css [[:some-class {:color "#000"}]]}
(dom/div {::fp/class :some-class} "bla"))
(defsc SomeClass [this props _ css]
{:css [[:some-class {:color "#000"}]
[:other-class {:background "#fff"}]]}
(dom/div {::fp/class [:some-class :other-class]} "bla"))
(maybe use ::css/class
instead, thinking now this keyword makes more sense on css namespace)
I was thinking convert at macro read time
is it? by using a fully qualified namespace it can be easy to walk and replace the values
i’d rather have less boilerplate, ^ solution seems worse IMO
(defmacro X [stuff]
(div ... use your stuff))
(defmacro div ...)
(defsc (which is a macro) (X ...))
it’s the same composition problem: I can’t figure out what component I’m nested in reliably
in this case they’re all macros, but combine in some symbols that have to be evaluated at runtime and you lose all composition
what I was thinking is: the defsc
always know the full symbol, and it runs before the div
macro, in this case I'm cutting out the possibility for symbols here, you should only use the keywords so it gets easy to translate into the full class names
if you need to use symbols for dynamic class, fallback to other solutions
@tony.kay In development - I am seeing [fulcro.client.primitives] component nycdvp.ui.property/PropertyDetail's ident ([:property/by-bbl nil]) has a nil second element. This warning can be safely ignored if that is intended.
after I click on a row that triggers a server load. The property detail page then updates once the data is in. On production server (with ‘release’ build), however, clicking on a property results in the whole screen going blank - and an Uncaught TypeError: Cannot read property 'log' of null
which I haven’t investigated yet. Is there something I need to do to prevent the nil second element during a load - is it an issue? Heading to fulcro.book now to research.
@donmullen are you using React 16?
uncaught exceptions do that in React 16...you have to define more code to isolate them. That warning, as you found, typically means there is some kind of data disconnect