This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-11-07
Channels
- # bangalore-clj (1)
- # beginners (255)
- # boot (29)
- # cider (16)
- # cljs-dev (13)
- # cljsrn (6)
- # clojure (200)
- # clojure-berlin (1)
- # clojure-dev (13)
- # clojure-dusseldorf (6)
- # clojure-greece (1)
- # clojure-india (1)
- # clojure-italy (1)
- # clojure-russia (33)
- # clojure-spec (28)
- # clojure-uk (27)
- # clojurescript (47)
- # cursive (32)
- # data-science (3)
- # datascript (1)
- # datomic (40)
- # emacs (39)
- # events (4)
- # fulcro (55)
- # graphql (16)
- # immutant (2)
- # luminus (2)
- # lumo (5)
- # off-topic (142)
- # onyx (50)
- # portkey (1)
- # re-frame (45)
- # reagent (80)
- # remote-jobs (2)
- # ring-swagger (3)
- # rum (9)
- # schema (3)
- # shadow-cljs (184)
- # spacemacs (3)
- # test-check (4)
- # unrepl (2)
- # yada (5)
form's commit-to-entity!
might have a weakness. It checks if form is valid outside of transact!, to construct the transaction. In a multithreaded environment that might become a problem?
also I still haven't figured out how to chain additional mutations to commit-to-entity!
if it succeeds. I'd say that's a very common use-case.
Hello all, hope all are well. I noticed a few interesting things and would welcome people's thoughts. (1) I moved over code from a not-quite-properly built fulcro codebase to one built with the fulcro lein template (thanks Tony!) and noticed that 'classes' inside cljs files were not being seen in the build process. Changing them to .cljc worked well. This is interesting (if it's a design decision) because the UI code is very much cljs only, correct? Is cljc more appropriate for a certain reason in this case? (2) Too, the upsert-css function was not being found despite importing it correctly and I wonder if this is because I was (now) calling it from a cljc? (Hope I'm not being dumb here).
@eugekev have you tried lein clean
and rebuilding everything ? .cljs
should work just as well, cljc only if you have ssr.
@eugekev upsert-css
is cljs only so you should put that in a reader conditional
Thanks @claudiu I'm pretty sure I did. @mitchelkuijpers - will definitely do so, thanks. I took it out for the moment to see if it worked and that was fine. Perhaps the lack of the reader conditional in the cljc was the problem. đ Cheers to you both.
@claudiu Yes, even after a lein clean, renaming the filename for the component from .cljc to .cljs causes a
Exception in thread "main" java.io.FileNotFoundException: Could not locate test_fulcro/ui/homepage__init.class or test_fulcro/ui/homepage.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name., compiling:(root.cljc:1:1)
@eugekev did you rename all the files UI to cljs ? looks like there's some component on the "server" side that tries to import that one. The template has ssr, on the server side in server.clj
need to be remov those imports and "def top-html" to generate only the container div.
@roklenarcic commit to entity is not really what you should use as your primary tool for most forms, because it isnât composable with other mutations. The stuff in the dev guide about custom form submission is probably going to be a more common thing. Now, on âhow do I tell if the submit went ok?â You have several options. The first thing you should do, though, is change your thinking a bit. Admit youâre in a distributed system. A submit is a write to a remote. A result is a read from a remote. Fulcroâs model is one where data cannot flow in unless there is an explicit query (how else would it know where to put that data?) So, mutations can have a return value. If you want to use that route, then you have to make custom form submission mutations, and configure the mutation merge functionality so you can capture the returns and do something with them. You could also simply treat your âstatus checkâ as an explicit read. Fulcro sequences mutations first on the network, and this would give you the explicit query for proper merge (and post mutation support).
BTW: To anyone lurking: this is one of the core concepts about any kind of âresultâ (read after write). In Fulcro, if you have to know the result of a write, you have to explicitly read it, or add a merge handler for itâŚotherwise there is nothing Fulcro can do with the result..itâs your database.
In REST-based systems, we were used to âresponse codesâ and such from our POST. If you think about it, that is a much more complicated way of dealing with results. There is no structure to it. Every response from POST had a different JSON blob of explanation with no schema. It implies weâre going to lean on the server for validation (way old-school). The interface to it leads to callback hell because youâve got async stuff going on. There are these weird codes that you may or may not have mapped properly from the standard. There is the fact that a lot of them would just be ignored anyway (we trust the server is going to succeed most of the time, and often program that way). With Fulcro, unifying all input from the server around queries and responses is what gives us the ability to reason about the data model in a very simple and consistent way (it is just a normalized graph). Finally, and this requires a bit more work, but might be worth it: Why is your form submit failing at the server??? Iâve talked about error handling before. Your code really should be robust, so except for bugs your submit should work. Youâve got the minimum delta. Most apps can tolerate last-write-wins. There is nothing that can fail that you can do anything aboutâŚ.except network errors. Recoverable network errors imply retry. So, Iâm hoping that we start to evolve our ways of interacting with users to where they only see bad results from the server where there is something seriously wrongâŚbut at that point theyâre just going to have a bad experience, so some kind of global error handler that pops up a modal of âthings went south in a bad wayâ become sufficient. This is a good result đ
So, the model Iâd suggest is this (and Iâm working on making this less code for you to write in 2.0): 1. If you need to ask about the result of something use explicit remote reads that you queue with your write. Youâve now given an explicit schema to your interaction. 2. Make your server submissions idempotent by saving the uuid of tempids in your database (that way if you managed to write it on the server before the error occurred, you can just re-send the tempid remaps). Similar scheme for other submissions⌠3. (2) allows you to write a custom network handler that can safely auto-retry on network errors. 4. Add a global error handler to (3) that knows about the reconciler, and can trigger a modal when things go very badly (or you want to give up on retries) 5. (coming soon). With history it is even possible to rewind the userâs session in the UI to the last place you were able to talk to the server. This is not entirely possible yet, but will be with 2.0. Give them the option to re-submit the entire failed sequence (it will be in history), or just resume at the last known good spot.
I think an acceptable (and easier-to-write) version of this is just to assume things will go well, and have a global network error handler than can report when things have gone south and re-start the user in a decent known state (maybe even returning them to a home page for code simplicity). It is rarely going to happen unless you have lots of bugs, so most ppl will find this quite an acceptable experience. In this model the server just throws an exception when it is unhappy, and triggers that global error handler.
Why is your form submit failing at the server???
-> if server is down I don't want to close the form. What I was hoping for is simply an ability to say: if fallback handler wasn't triggered then run this mutation vector.
I'll admit it's a much smaller scope of considering error handling than what you wrote
I wasn't looking to handle any special error circumstances
I think when something goes south and you've clicked save/submit in a dialog, you'll want to not run the "dialog close" mutation. The error popup is handled by fallback function obviously
Youâre assuming synchronous operation (wait to close the form until I know it got there)?
I see what you're getting at.
Honestly error handling is one of the pain points of software development right now
So, here is the way to do that:
1. Submit the form, and disable all user interactions (e.g. with a state variable like :ui/submission-in-progress?
)
2. Send a load to ask about the resultâŚ
3. The post-mutation on (2) flips the :ui/submission-in-progress?
back to false, and can optionally auto-close the form.
You can do exactly what you want in Fulcro, just remember what the default model is đ
I agree with you about error handlingâŚI think we actually have a really great story, but it is different
Bugs are not a problem for me. I don't expect error states based on bugs
But you did alert me to the possiblity of user clicking save button multiple times while requests are in flight
I generally âblock UIâ with soemthing like a transparent overlay that doesnât bubble events
Error handling stories are a funny thing. OOP brought exceptions but in experience of last 10 years, nobody ever attempts to recover from them
they just wrap try catch -> log exception
I think it's why Rust lang went back to C style error codes
I find error codes to be superior to exceptions because people tend to aggregate several exception scenarios into one exception class, and it varies by exception text, which is terrible data to dispatch on.
Having exception messages on exceptions themselves is quite a blunder IMO
The number of programs I've seen that blurt out exception message (in english, even when locale is not so) to the end user in my career is staggering
But I'll look into your suggestions. I'm not making a very complicated app and it doesn't have complex exceptional scenarios.
The "song" column contains a Hall and Oates song. The idea that Hall and Oates are software gurus is controversial in some circles, so you can treat this as flavortext.
As a Hall and Oates fan I appreciate that
Although they should have found a way to use Maneater đ
not at all complete by the looks
-> quite an understatement
Uh... I might be wrong (I don't know how to debug clojurescript), but forms validate-fields
function, when used on a form with no fields other than a subform that has actual fields, returns a value that forms valid?
returns false. It returns a value where the form, that contains no fields other than a subform, has all non-id fields marked as :unchecked.
I've been wrangling with this whole day and I don't know what to do.
I see what's going on. commit-to-entity!
checks if form is valid with validate-fields
which doesn't handle sub-forms, so they are returned as unchecked, so the first time commit-to-entity!
is called, only validate-form
is called. The second time I click the button, form is marked as validated and the entity is sent to server
@roklenarcic Thereâs likely an improvement that can be made there. The idea is that your commit button should not be available until youâve actually run validations on the form and the form is in state as valid. If commit detects that this is not the case, it runs validation and bails on the commit.