Liking cljdoc? Tell your friends :D

com.fulcrologic.fulcro.algorithms.form-state

Functions that assist with supporting form editing/checking/diffing in Fulcro UI. These functions work by making a pristine copy of your entity, and tracking what fields have been touched. You are responsible for triggering these various states by marking fields as complete (mark-complete!), telling it to copy the data to/from pristine (e.g. entity->pristine), and by asking for out-of-date data for the current vs. pristine copy (dirty-fields).

There is also support for detecting which fields have been marked complete and are dirty.

Validation can be done via Clojure spec (not recommended), or by defining your own field validation functions via make-validator (recommended). This general-purpose validation factory function can easily be used to create more automated validation factories that can be more configuration-driven, but this is left as an exercise for the community.

Specs are not recommended because forms commonly have multi-field dependencies that simply are not well-supported, and sometimes the use of things like Fulcro tempids leads to specs that you'd rather not have on your server. Use of spec really boils down to your intention for those spec (i.e. hard validation of final database value vs. potential runtime look of the data as it is manipulated). Specs that include "state" information will cause you more pain than you want, though you can certainly leverage specs anywhere it makes sense using the validator factory.

IMPORTANT: This namespace is about (possibly recursive) form data management. Rendering and such are not part of the stated intention. See Fulcro RAD for more fully-automated, multi-platform form generation.

See the Developer's Guide for more information.

Functions that assist with supporting form editing/checking/diffing in Fulcro UI.  These functions work
by making a pristine copy of your entity, and tracking what fields have been touched.  You are responsible
for triggering these various states by marking fields as complete (`mark-complete!`), telling it to
copy the data to/from pristine (e.g. `entity->pristine`), and by asking for out-of-date data for the current
vs. pristine copy (`dirty-fields`).

There is also support for detecting which fields have been marked complete and are dirty.

Validation can be done via Clojure spec (not recommended), or by defining your own field validation functions via
`make-validator` (recommended). This general-purpose validation factory function can easily be used to create more
automated validation factories that can be more configuration-driven, but this is left as an exercise for the community.

Specs are not recommended because forms commonly have multi-field dependencies that simply are
not well-supported, and sometimes the use of things like Fulcro tempids leads to specs that you'd
rather not have on your server. Use of spec really boils down to your intention for those
spec (i.e. hard validation of final database value vs. potential runtime look of the data as
it is manipulated). Specs that include "state" information will cause you more pain than
you want, though you can certainly leverage specs anywhere it makes sense using the validator factory.

IMPORTANT: This namespace is about *(possibly recursive) form data management*. Rendering and
such are not part of the stated intention. See Fulcro RAD for more fully-automated,
multi-platform form generation.

See the Developer's Guide for more information.
raw docstring

add-form-configclj/s

(add-form-config class entity)
(add-form-config class entity {:keys [destructive?] :as opts})

Add form configuration data to a denormalized entity (e.g. pre-merge). This is useful in initial state or when using merge-component!. This function will not touch an entity that already has form config but will recurse the entire form set. It can therefore be invoked on the top-level of the form set when adding, for example, an instance of a sub-form.

class - The component class. entity - A denormalized (tree) of data that matches the given component class. opts map

  • :destructive? - If true, overwrites any previous form-config with new re-computed values.

Returns the (possibly updated) denormalized entity, ready to merge.

Add form configuration data to a *denormalized* entity (e.g. pre-merge). This is useful in
initial state or when using `merge-component!`. This function *will not* touch an entity
that already has form config but will recurse the entire form set. It can therefore be
invoked on the top-level of the form set when adding, for example, an instance of a sub-form.

class - The component class.
entity - A denormalized (tree) of data that matches the given component class.
opts map
  - :destructive? - If true, overwrites any previous form-config with new re-computed values.

Returns the (possibly updated) denormalized entity, ready to merge.
sourceraw docstring

add-form-config*clj/s

(add-form-config* state-map class entity-ident)
(add-form-config* state-map class entity-ident {:keys [destructive?] :as opts})

Identical to add-form-config, but works against normalized entities in the app state. This makes it ideal for composition within mutations.

state-map - The application state database (map, not atom). class - The component class. Must have declared form fields. entity-ident - The ident of the normalized entity of the given class that you wish to initialize. opts map

  • :destructive? - If true, overwrites any previous form-config with new re-computed values.

Returns an updated state map with normalized form configuration in place for the entity.

Identical to `add-form-config`, but works against normalized entities in the
app state. This makes it ideal for composition within mutations.

state-map - The application state database (map, not atom).
class - The component class. Must have declared form fields.
entity-ident - The ident of the normalized entity of the given class that you wish to initialize.
opts map
  - :destructive? - If true, overwrites any previous form-config with new re-computed values.

Returns an updated state map with normalized form configuration in place for the entity.
sourceraw docstring

checked?clj/s

(checked? ui-form)
(checked? ui-form field)

Returns true if the field (or entire denormalized (UI) form) is ready to be checked for validation. Until this returns true validators will simply return :unchecked for a form/field.

Returns true if the field (or entire denormalized (UI) form) is ready to be checked for validation.
Until this returns true validators will simply return :unchecked for a form/field.
sourceraw docstring

clear-complete!clj/s

Mutation: Mark a given form (recursively) or field incomplete.

entity-ident - The ident of the entity to mark. This is optional, but if not supplied it will derive it from the ident of the invoking component. field - (optional) limit the marking to a single field.

See clear-complete* for a function you can compose into your own mutations.

Mutation: Mark a given form (recursively) or field incomplete.

entity-ident - The ident of the entity to mark. This is optional, but if not supplied it will derive it from
               the ident of the invoking component.
field - (optional) limit the marking to a single field.

See `clear-complete*` for a function you can compose into your own mutations.
sourceraw docstring

clear-complete*clj/s

(clear-complete* state-map entity-ident)
(clear-complete* state-map entity-ident field)

Mark the fields incomplete so that validation checks will no longer return values. This function works on an app state database map (not atom) and is meant to be composed into mutations. See the mark-incomplete! mutation if you do not need to combine this with other operations.

Follows the subforms recursively through state, unless a specific field is given.

Mark the fields incomplete so that validation checks will no longer return values. This function works on an app state database
map (not atom) and is meant to be composed into mutations. See the `mark-incomplete!` mutation if you do not need to combine
this with other operations.

Follows the subforms recursively through state, unless a specific field is given.
sourceraw docstring

completed-form-propsclj/s

(completed-form-props state-map form-class form-ident)

Calculates and returns the (ui) props of the given form-class based upon marking the form in the given state-map complete, and then using the query of the form-class to pull the props. This function is useful in mutations and other back-end logic that has access to the Fulcro database, but needs to call other support functions in this namespace where the form props are required.

  • state-map: The Fulcro normalized database
  • form-class: The form component class (an instance is also acceptable)
  • form-ident: The ident of the form instance to pull props for.

Returns a tree of UI props where all fields have been marked complete.

Calculates and returns the (ui) props of the given form-class based upon marking the form in the given state-map
complete, and then using the query of the form-class to pull the props. This function is useful in mutations and
other back-end logic that has access to the Fulcro database, but needs to call other support functions in this
namespace where the form props are required.

- `state-map`: The Fulcro normalized database
- `form-class`: The form component class (an instance is also acceptable)
- `form-ident`: The ident of the form instance to pull props for.

Returns a tree of UI props where all fields have been marked complete.
sourceraw docstring

delete-form-state*clj/s

(delete-form-state* state-map entity-ident-or-idents)

Removes copies of entities used by form-state logic.

Removes copies of entities used by form-state logic.
sourceraw docstring

dirty-fieldsclj/s

(dirty-fields ui-entity as-delta?)
(dirty-fields ui-entity as-delta? {:keys [new-entity?] :as opts})

Obtains all of the dirty fields for the given (denormalized) ui-entity, recursively. This works against UI props because submission mutations should close over the data as parameters to a mutation. In other words, your form submission to a server should be triggered from UI with the output of this function as parameters:

(dom/input { :onClick #(comp/transact! this `[(some-submit-function {:diff ~(f/dirty-fields props true)})]) })
  • ui-entity - The entity (denormalized) from the UI.
  • as-delta? - If false, each field's reported (new) value will just be the new value. When true, each value will be a map with :before and :after keys with the old and new values (useful for optimistic transaction semantics).

Returns a map keyed by form ID (for each form/subform) whose values are maps of key/value pairs of changes. Fields from entities that have a temporary IDs will always be included.

In other words, a change that happened for an entity with ident entity-ident on field :field:

With as-delta? true:

{entity-ident {:field {:before 1 :after 2}}}

with as-delta? false:

{entity-ident {:field 2}}

If ui-entity has tempid in ident or has :new-entity? true in opts map, then all fields for that form will be included in result regardless of pristine state.

Obtains all of the dirty fields for the given (denormalized) ui-entity, recursively. This works against UI props
because submission mutations should close over the data as parameters to a mutation. In other words, your form
submission to a server should be triggered from UI with the output of this function as parameters:

```
(dom/input { :onClick #(comp/transact! this `[(some-submit-function {:diff ~(f/dirty-fields props true)})]) })
```

- `ui-entity` - The entity (denormalized) from the UI.
- `as-delta?` - If false, each field's reported (new) value will just be the new value. When true, each value will be a map with :before and :after keys
with the old and new values (useful for optimistic transaction semantics).

Returns a map keyed by form ID (for each form/subform) whose values are maps of key/value pairs of
changes. Fields from entities that have a temporary IDs will always be included.

In other words, a change that happened for an entity with ident `entity-ident` on field `:field`:

With `as-delta?` true:

```
{entity-ident {:field {:before 1 :after 2}}}
```

with `as-delta?` false:

```
{entity-ident {:field 2}}
```

If ui-entity has tempid in ident or has `:new-entity? true` in opts map, then all fields for that form will be
included in result regardless of pristine state.
sourceraw docstring

dirty?clj/s

(dirty? ui-entity-props)
(dirty? ui-entity-props field)

Returns true if the given ui-entity-props that are configured as a form differ from the pristine version. Recursively follows subforms if given no field. Returns true if anything doesn't match up.

If given a field, it only checks that field.

Returns true if the given ui-entity-props that are configured as a form differ from the pristine version.
Recursively follows subforms if given no field. Returns true if anything doesn't match up.

If given a field, it only checks that field.
sourceraw docstring

entity->pristine*clj/s

(entity->pristine* state-map entity-ident)

Overwrite the pristine state (form state's copy) of the entity. This is meant to be used from a mutation to update the form state tracking recursively to make the form as 'unmodified'. That is to say, as if you committed the values to the server, and the current entity state is now the pristine state.

This function does no sanity checks, so you should ensure the entity is valid!

Recursively updates all sub forms.

Returns the updated state-map (database).

Overwrite the pristine state (form state's copy) of the entity. This is meant to be used from a mutation
to update the form state tracking recursively to make the form as 'unmodified'. That is to say, as if you
committed the values to the server, and the current entity state is now the pristine state.

This function does no sanity checks, so you should ensure the entity is valid!

Recursively updates all sub forms.

Returns the updated state-map (database).
sourceraw docstring

form-configclj/s

(form-config entity-ident fields)
(form-config entity-ident fields subforms)

Generate a form config given:

entity-ident - The ident of the entity you're configuring forms for. fields - A set of keywords on the entity that is the form. subforms - An optional set of keywords on the entity that is the form, for the joins to subforms.

Generate a form config given:

entity-ident - The ident of the entity you're configuring forms for.
fields - A set of keywords on the entity that is the form.
subforms - An optional set of keywords on the entity that is the form, for the joins to subforms.
sourceraw docstring

form-config-joinclj/s

A query join to ::form-config. This should be added to the query of a component that is using form state support.

A query join to ::form-config. This should be added to the query of a component that is
using form state support.
sourceraw docstring

form-idclj/s

(form-id entity-ident)

Returns the form database table ID for the given entity ident.

Returns the form database table ID for the given entity ident.
sourceraw docstring

formcclj/s

(formc EQL)
(formc EQL top-component-options)

Create an anonymous normalizing form component from EQL. Every level of the query MUST have an :<???>/id field which is used to build the ident, and every non-id attribute will be considered part of the form except:

  • Props in the namespace ui like :ui/checked?
  • Idents list [:component/id :thing]
  • Root links like [:root/key '_]

This function also auto-adds the necessary form-state form join, and populates the anonymous component with the :form-fields option. You can add additional component options to the top-level anonymous component with top-component-options.

See also nc, which is similar but does not autogenerate form-related add-ins.

Create an anonymous normalizing form component from EQL. Every level of the query MUST
have an `:<???>/id` field which is used to build the ident, and every non-id attribute will be considered part
of the form except:

* Props in the namespace `ui` like `:ui/checked?`
* Idents list `[:component/id :thing]`
* Root links like `[:root/key '_]`

This function also auto-adds the necessary form-state form join, and populates the anonymous component with the
`:form-fields` option. You can add additional component options to the top-level anonymous component with
`top-component-options`.

See also `nc`, which is similar but does not autogenerate form-related add-ins.
sourceraw docstring

FormConfigclj/s

A normalizing component supporting normalization of form state configuration. Not really for direct use.

A normalizing component supporting normalization of form state configuration. Not really for direct use.
sourceraw docstring

get-form-fieldsclj/s

(get-form-fields class)

Returns the set of defined form fields for the given component class (or instance).

Returns the set of defined form fields for the given component class (or instance).
sourceraw docstring

get-spec-validityclj/s

(get-spec-validity form)
(get-spec-validity form field)

Get the validity (:valid :invalid or :unchecked) for the given form/field using Clojure specs of the field keys.

  • ui-entity-props : A denormalized (UI) entity, which can have subforms.
  • field : Optional. Returns the validity of just the single field on the top-level form.

Returns :invalid if all of the fields have been interacted with, and any are invalid.

Returns :unchecked if any field is not yet been interacted with.

Fields are marked as having been interacted with by programmatic action on your part via the validate* mutation helper can be used in a mutation to mark fields ready for validation.

If given a field then it checks just that field.

Get the validity (:valid :invalid or :unchecked) for the given form/field using Clojure specs of the field keys.

- `ui-entity-props` : A denormalized (UI) entity, which can have subforms.
- `field` : Optional. Returns the validity of just the single field on the top-level form.

Returns `:invalid` if all of the fields have been interacted with, and *any* are invalid.

Returns `:unchecked` if any field is not yet been interacted with.

Fields are marked as having been interacted with by programmatic action on your part via
the validate* mutation helper can be used in a mutation to mark fields ready for validation.

If given a field then it checks just that field.
sourceraw docstring

ident-generatorclj/s

source

immediate-subform-identsclj/s

(immediate-subform-idents entity subform-join-keys)

Get the idents of the immediate subforms that are joined into entity by subform-join-keys (works with to-one and to-many). Entity is a NORMALIZED entity from the state map.

Returns a sequence of those idents.

Get the idents of the immediate subforms that are joined into entity by
subform-join-keys (works with to-one and to-many). Entity is a NORMALIZED entity from the state map.

Returns a sequence of those idents.
sourceraw docstring

immediate-subformsclj/s

(immediate-subforms entity subform-join-keys)

Get the instances of the immediate subforms that are joined into the given entity by subform-join-keys (works with to-one and to-many).

  • entity - a denormalized (UI) entity.
  • subform-join-keys - The keys of the subforms of this entity, as a set.

Returns a sequence of those entities (all denormalized).

Get the instances of the immediate subforms that are joined into the given entity by
subform-join-keys (works with to-one and to-many).

- `entity` - a denormalized (UI) entity.
- `subform-join-keys` - The keys of the subforms of this entity, as a set.

Returns a sequence of those entities (all denormalized).
sourceraw docstring

invalid-spec?clj/s

(invalid-spec? ui-form)
(invalid-spec? ui-form field)

Returns true if the given field (or any field if only a form is given) in the denormalized (UI) form is :invalid (recursively) according to clojure specs. Returns false if the field is marked unchecked. Use checked-spec? or get-spec-validity for better detail.

Returns true if the given field (or any field if only a form is given) in the denormalized (UI) form is :invalid
(recursively) according to clojure specs. Returns false if the field is marked unchecked. Use `checked-spec?` or
`get-spec-validity` for better detail.
sourceraw docstring

make-validatorclj/s

(make-validator field-valid?)
(make-validator field-valid? {:keys [validate-edges?]})

Create a form/field validation function using a supplied field checker. The field checker will be given then entire form (denormalized) and a single field key that is to be checked. It must return a boolean indicating if that given field is valid.

During a recursive check for a form, the validation function will be in the correct context (e.g. the form supplied will contain the field. There is no need to search for it in subforms).

The options map can contain:

  • validate-edges? (default false). When true, the validator will be run on joins that lead to subforms. Normally it runs only on non-join form fields.

make-validator returns a dual arity function:

  • (fn [form] ...) - Calling this version will return :unchecked, :valid, or :invalid for the entire form.
  • (fn [form field] ...) - Calling this version will return :unchecked, :valid, or :invalid for the single field.

Typical usage would be to show messages around the form fields:

(def field-valid? [form field] true) ; just say everything is valid

(def my-validator (make-validator field-valid?))

(defn valid? [form field]
   (= :valid (my-validator form field)))

(defn checked? [form field]
   (not= :unchecked (my-validator form field)))
Create a form/field validation function using a supplied field checker. The field checker will be given
then entire form (denormalized) and a single field key that is to be checked. It must return
a boolean indicating if that given field is valid.

During a recursive check for a form, the validation function will be in the correct context (e.g. the form supplied will contain
the field. There is no need to search for it in subforms).

The options map can contain:

* `validate-edges?` (default false). When true, the validator will be run on joins that lead to subforms. Normally it runs only on non-join
form fields.

make-validator returns a dual arity function:

- `(fn [form] ...)` - Calling this version will return :unchecked, :valid, or :invalid for the entire form.
- `(fn [form field] ...)` - Calling this version will return :unchecked, :valid, or :invalid for the single field.

Typical usage would be to show messages around the form fields:

```
(def field-valid? [form field] true) ; just say everything is valid

(def my-validator (make-validator field-valid?))

(defn valid? [form field]
   (= :valid (my-validator form field)))

(defn checked? [form field]
   (not= :unchecked (my-validator form field)))
```
sourceraw docstring

mark-complete!clj/s

Mutation: Mark a given form (recursively) or field complete.

entity-ident - The ident of the entity to mark complete. This is optional, but if not supplied it will derive it from the ident of the invoking component. field - (optional) limit the marking to a single field.

See mark-complete* for a function you can compose into your own mutations.

Mutation: Mark a given form (recursively) or field complete.

entity-ident - The ident of the entity to mark complete. This is optional, but if not supplied it will derive it from
               the ident of the invoking component.
field - (optional) limit the marking to a single field.

See `mark-complete*` for a function you can compose into your own mutations.
sourceraw docstring

mark-complete*clj/s

(mark-complete* state-map entity-ident)
(mark-complete* state-map entity-ident field)

Mark the fields complete so that validation checks will return values. This function works on a app state database map (not atom) and is meant to be composed into mutations. See the mark-complete! mutation if you do not need to combine this with other operations.

Follows the subforms recursively through state, unless a specific field is given.

Mark the fields complete so that validation checks will return values. This function works on a app state database
map (not atom) and is meant to be composed into mutations. See the `mark-complete!` mutation if you do not need to combine
this with other operations.

Follows the subforms recursively through state, unless a specific field is given.
sourceraw docstring

no-spec-or-valid?clj/s

(no-spec-or-valid? entity-props key)

Returns false if and only if the given key has a spec, and the spec is not valid for the value found in the given map of entity props (e.g. (s/valid? key (get entity-props key))).

Returns true otherwise.

Returns false if and only if the given key has a spec, and the spec is not valid for the value found in the given
map of entity props (e.g. `(s/valid? key (get entity-props key))`).

Returns true otherwise.
sourceraw docstring

pristine->entity*clj/s

(pristine->entity* state-map entity-ident)

Copy the pristine state over top of the originating entity of the given form. Meant to be used inside of a mutation. Recursively follows subforms in app state. Returns the new app state map.

state-map - The normalized state database (map, not atom) entity-ident - The ident of the entity that you wish to restore to its original pristine state.

Only affects declared fields and sub-forms.

Copy the pristine state over top of the originating entity of the given form. Meant to be used inside of a
mutation. Recursively follows subforms in app state. Returns the new app state map.

state-map - The normalized state database (map, not atom)
entity-ident - The ident of the entity that you wish to restore to its original pristine state.

Only affects declared fields and sub-forms.
sourceraw docstring

reset-form!clj/s

Mutation: Reset the form (recursively) to its (last recorded) pristine state. If form ident is not supplied it uses the ident of the calling component. See pristine->entity* for a function you can compose into your own mutations.

Mutation: Reset the form (recursively) to its (last recorded) pristine state. If form ident is not supplied it uses the ident
of the calling component. See `pristine->entity*` for a function you can compose into your own mutations.
sourceraw docstring

update-formsclj/s

(update-forms state-map xform starting-entity-ident)

Recursively update a form and its subforms. This function works against the state database (normalized state).

state-map : The application state map xform : A function (fn [entity form-config] [entity' form-config']) that is passed the normalized entity and form-config, and must return an updated version of them. starting-entity-ident : An ident in the state map of an entity that has been initialized as a form.

Returns the updated state map.

Recursively update a form and its subforms. This function works against the state database (normalized state).

`state-map` : The application state map
`xform` : A function (fn [entity form-config] [entity' form-config']) that is passed the normalized entity and form-config,
  and must return an updated version of them.
`starting-entity-ident` : An ident in the state map of an entity that has been initialized as a form.

Returns the updated state map.
sourceraw docstring

valid-spec?clj/s

(valid-spec? ui-form)
(valid-spec? ui-form field)

Returns true if the given field (or the entire denormalized (UI) form recursively) is :valid according to clojure specs. Returns false if unchecked or invalid. Use checked-spec? or get-spec-validity for better detail.

Returns true if the given field (or the entire denormalized (UI) form recursively) is :valid
according to clojure specs. Returns false if unchecked or invalid. Use `checked-spec?` or `get-spec-validity`
for better detail.
sourceraw docstring

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close