Fork me on GitHub
#fulcro
<
2023-11-23
>
Tobias Burger15:11:59

Extending my customized registration form I want now to redirect to a thank you page. What works is to redirect to the "cancel" route by calling :event/cancel like so:

(defsc-form ...
{...
fo/triggers {:saved (fn [{::uism/keys [fulcro-app] :as uism-env} ident]
                         (-> uism-env
                             (uism/trigger ident :event/cancel)))}
}
...)
But I want to redirect to a ThankYou page which has access to the form state. I've tried the following approaches: • Define a custom override for the :saved fo/trigger and route-to! another page (providing additional data via parameters). • Define a custom state machine event, register it with fo/machine and trigger the event when calling the :saved fo/trigger. For the first approach I've done the following:
fo/triggers {:saved (fn [{::uism/keys [fulcro-app] :as uism-env} ident]
                         (scheduling/defer (rad-routing/route-to! fulcro-app ThankYou {}) 100)
                         uism-env)}
The code for the deferred routing I've copied from the form/leave-form code. But this has the disadvantage that the form get's detected as "dirty" and I get a warning, if I am sure I want to leave the page. So I am quite sure this is NOT the correct way to handle such a situation. So my next approach was to override the predefined state machine, but I get an error that the event is not defined for the state:
(def registration-machine
  (-> form/form-machine
      (assoc-in [::uism/states :state/editing ::uism/events :event/registered]
                {::uism/handler form/leave-form}))) ;; for example i call leave-form like :event/cancel

(defsc-form ...
  {...
   fo/machine registration-machine
   fo/triggers {:saved (fn [uism-env ident]
                         (-> uism-env
                             (uism/trigger ident :event/registered)))}
  }...)
But this produces the warning and nothing else happens: > UNEXPECTED EVENT: Did not find a way to handle event :event/registered in the current active state: :state/editing See https://book.fulcrologic.com/#warn-uism-unexpected-event I don't understand what I am doing wrong here. When I inspect the registration-machine the event is defined on the correct active state but somehow the state machine doesn't find this event. So I wonder what is the correct way of handling such a scenario?

tony.kay04:11:23

Nothing is popping out at me, but have you considered that the state machine is just dealing with the form. You could add a render body to the form and wrap the plugin rendering:

(defsc-form ...
 {...}
 (div 
    (form/render-layout ...)
    (when-not (fs/dirty? ...)
      (dom/button {:onClick (fn [] ...routing...)}))))
and just take your “post action” out of the entire mix.

Jakub Holý (HolyJak)21:11:30

Perhaps there is a typo somewhere in your code, or some other small mistake that screws it up? You could add a log (or breakpoint) to the point where the error is printed to inspect what the SM really looks like at the point. Have you registered your modified uism correctly for that form?

Tobias Burger10:12:45

Sorry for my long delay to answer. I've tried the simple approach by rerouting when clicking the form but couldn't come up with a solution to reliably save AND reroute on a single button click. I don't want to display a new button after the user has saved the form. I am sure I am missing something but as far as I understand the save! does only execute the optimistic part synchronously so I need some way to wait for a successful save roundtrip. Nevertheless I got to the conclusion that in order to cleanly solve the problem I need to derive a new state machine. And indeed I finally found my error: in order to derive from an existing state machine the derived state machine needs also to be a registered state machine. I've completely overlooked that fact and directly derived from the existing state machine without defining/registering a new one (using def instead of defstatemachine). I've completely overlooked that part! So the full working code is as following:

(defn after-registration
  [{::uism/keys [fulcro-app] :as uism-env}]
  (let [Form           (uism/actor-class uism-env :actor/form)
        form-ident     (uism/actor->ident uism-env :actor/form)
        state-map      ( fulcro-app)
        props (fns/ui->props state-map Form form-ident)
        registered-route   (?! (some-> Form comp/component-options ::form/registered-route) fulcro-app props)
        routing-action (fn [] (dr/change-route! fulcro-app registered-route props))]
    (sched/defer routing-action 100)
    uism-env))

(defstatemachine registration-form-machine
  (-> form/form-machine
      (assoc-in [::uism/states :state/editing ::uism/events :event/registered ::uism/handler] after-registration)))
Now the state machine can be registered and the save event can be overwritten:
(form-defsc-form RegistrationForm [this props]
{,,,
 form/machine registration-form-machine
 fo/triggers {:saved (fn [uism-env ident]
                         (-> uism-env
                             (uism/trigger ident :event/registered)))}
,,,})

🙏 1