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.
(add-form-config class entity)
(add-form-config class entity {:keys [new? destructive? state-map] :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
class
.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. - :new? - If true (default true when the entity has a tempid, otherwise false), do not copy any data to the pristine state. - :state-map - If present, will support dynamic queries on the `class`. Returns the (possibly updated) denormalized entity, ready to merge.
(add-form-config* state-map class entity-ident)
(add-form-config* state-map
class
entity-ident
{:keys [destructive? new?] :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
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. - :new? - Default is true if ident uses a tempid. When new, no pristine state is stored in the form config. Returns an updated state map with normalized form configuration in place for the entity.
(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.
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.
(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.
(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 databaseform-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.
(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.
(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.
(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.
(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).
(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.
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.
(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.
(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:
ui
like :ui/checked?
[:component/id :thing]
[: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.
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.
(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).
(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.
(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.
(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).
(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.
(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))) ```
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.
(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.
(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.
(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.
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.
(update-forms state-map xform starting-entity-ident)
(update-forms state-map xform starting-entity-ident idents-visited)
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.
(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.
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close