HTML::FormFu(3pm)

πŸ“¦
version 2.07000 Β· 5 versions
, in debian bookworm, ubuntu jammy, ubuntu noble

✨ NAME ✨

okay so bestie, this is the HTML::FormFu(3pm) page from the User Contributed Perl Documentation πŸ’–. The module is HTML::FormFu β€” HTML Form Creation, Rendering and Validation Framework. That's the whole vibe: forms, rendering, validation, slay. ✨


🌸 VERSION 🌸

version 2.07 β€” no cap, that's the version. πŸ’…


πŸ¦‹ SYNOPSIS πŸ¦‹

Note: These examples make use of HTML::FormFu::Model::DBIC. As of "HTML::FormFu" v02.005, the HTML::FormFu::Model::DBIC module is not bundled with "HTML::FormFu" and is available in a stand-alone distribution. iykyk
use HTML::FormFu;

my $form = HTML::FormFu->new;

$form->load_config_file('form.yml');

$form->process( $cgi_query );

if ( $form->submitted_and_valid ) {
    # do something with $form->params
}
else {
    # display the form
    $template->param( form => $form );
}

If you're using Catalyst, a more suitable example might be:

package MyApp::Controller::User;
use Moose;
extends 'Catalyst::Controller::HTML::FormFu';

sub user : Chained CaptureArgs(1) {
    my ( $self, $c, $id ) = @_;

    my $rs = $c->model('Schema')->resultset('User');

    $c->stash->{user} = $rs->find( $id );

    return;
}

sub edit : Chained('user') Args(0) FormConfig {
    my ( $self, $c ) = @_;

    my $form = $c->stash->{form};
    my $user = $c->stash->{user};

    if ( $form->submitted_and_valid ) {

        $form->model->update( $user );

        $c->res->redirect( $c->uri_for( "/user/$id" ) );
        return;
    }

    $form->model->default_values( $user )
        if ! $form->submitted;

}
Note: Because process is automatically called for you by the Catalyst controller; if you make any modifications to the form within your action method, such as adding or changing elements, adding constraints, etc; you must call process again yourself before using submitted_and_valid, any of the methods listed under SUBMITTED FORM VALUES AND ERRORS or MODIFYING A SUBMITTED FORM, or rendering the form.

Here's an example of a config file to create a basic login form (all examples here are YAML, but you can use any format supported by Config::Any), you can also create forms directly in your perl code, rather than using an external config file.

---
action: /login
indicator: submit
auto_fieldset: 1

elements:
  - type: Text
    name: user
    constraints:
      - Required

  - type: Password
    name: pass
    constraints:
      - Required

  - type: Submit
    name: submit

constraints:
  - SingleValue

πŸ’œ DESCRIPTION πŸ’œ

HTML::FormFu is a HTML form framework which aims to be as easy as possible to use for basic web forms, but with the power and flexibility to do anything else you might want to do (as long as it involves forms). iconic honestly πŸ’–

You can configure almost any part of formfu's behaviour and output. By default formfu renders "XHTML 1.0 Strict" compliant markup, with as little extra markup as possible, but with sufficient CSS class names to allow for a wide-range of output styles to be generated by changing only the CSS. obsessed with the CSS-only glow-up ✨

All methods listed below (except new) can either be called as a normal method on your $form object, or as an option in your config file. Examples will mainly be shown in YAML config syntax.

This documentation follows the convention that method arguments surrounded by square brackets [] are optional, and all other arguments are required. important bestie!


πŸ‘‘ BUILDING A FORM πŸ‘‘

✨ new ✨

Arguments: [\%options]

Return Value: $form

Create a new HTML::FormFu object.

Any method which can be called on the HTML::FormFu object may instead be passed as an argument to new.

my $form = HTML::FormFu->new({
    action        => '/search',
    method        => 'GET',
    auto_fieldset => 1,
});

πŸŽ€ load_config_file πŸŽ€

Arguments: $filename

Arguments: \@filenames

Return Value: $form

Accepts a filename or list of file names, whose filetypes should be of any format recognized by Config::Any.

The content of each config file is passed to populate, and so are added to the form.

load_config_file may be called in a config file itself, so as to allow common settings to be kept in a single config file which may be loaded by any form.

---
load_config_file:
  - file1
  - file2

YAML multiple documents within a single file. The document start marker is a line containing 3 dashes. Multiple documents will be applied in order, just as if multiple filenames had been given.

In the following example, multiple documents are taken advantage of to load another config file after the elements are added. (If this were a single document, the load_config_file would be called before elements, regardless of its position in the file).

---
elements:
  - name: one
  - name: two

---
load_config_file: ext.yml

Relative paths are resolved from the config_file_path directory if it is set, otherwise from the current working directory.

See BEST PRACTICES for advice on organising config files.


🧚 config_callback 🧚

Arguments: \%options

If defined, the arguments are used to create a Data::Visitor::Callback object during load_config_file which may be used to pre-process the config before it is sent to populate.

For example, the code below adds a callback to a form that will dynamically alter any config value ending in .yml to end in .yaml when you call load_config_file:

$form->config_callback({
  plain_value => sub {
    my( $visitor, $data ) = @_;
    s/\.yml/.yaml/;
  }
});

Default Value: not defined

This method is a special 'inherited accessor', which means it can be set on the form, a block element or a single element. When the value is read, if no value is defined it automatically traverses the element's hierarchy of parents, through any block elements and up to the form, searching for a defined value.


πŸ“ populate πŸ“

Arguments: \%options

Return Value: $form

Each option key/value passed may be any HTML::FormFu method-name and arguments.

Provides a simple way to set multiple values, or add multiple elements to a form with a single method-call.

Attempts to call the method-names in a semi-intelligent order (see the source of populate() in HTML::FormFu::ObjectUtil for details).


🌈 default_values 🌈

Arguments: \%defaults

Return Value: $form

Set multiple field's default values from a single hash-ref.

The hash-ref's keys correspond to a form field's name, and the value is passed to the field's default method.

This should be called after all fields have been added to the form, and before process is called (otherwise, call process again before rendering the form).


πŸ¦‹ config_file_path πŸ¦‹

Arguments: $directory_name

config_file_path defines where configuration files will be searched for, if an absolute path is not given to load_config_file.

Default Value: not defined

This method is a special 'inherited accessor', which means it can be set on the form, a block element or a single element. When the value is read, if no value is defined it automatically traverses the element's hierarchy of parents, through any block elements and up to the form, searching for a defined value.

Is an inheriting accessor.


πŸ’… indicator πŸ’…

Arguments: $field_name

Arguments: \&coderef

If indicator is set to a fieldname, submitted will return true if a value for that fieldname was submitted.

If indicator is set to a code-ref, it will be called as a subroutine with the two arguments $form and $query, and its return value will be used as the return value for submitted.

If indicator is not set, submitted will return true if a value for any known fieldname was submitted.


✨ auto_fieldset ✨

Arguments: 1

Arguments: \%options

Return Value: $fieldset

This setting is suitable for most basic forms, and means you can generally ignore adding fieldsets yourself.

Calling $form->auto_fieldset(1) immediately adds a fieldset element to the form. Thereafter, $form->elements() will add all elements (except fieldsets) to that fieldset, rather than directly to the form.

To be specific, the elements are added to the last fieldset on the form, so if you add another fieldset, any further elements will be added to that fieldset.

Also, you may pass a hashref to auto_fieldset(), and this will be used to set defaults for the first fieldset created.

A few examples and their output, to demonstrate:

2 elements with no fieldset.

---
elements:
  - type: Text
    name: foo
  - type: Text
    name: bar
<form action="" method="post">
  <div class="text">
    <input name="foo" type="text" />
  </div>
  <div class="text">
    <input name="bar" type="text" />
  </div>
</form>

2 elements with an auto_fieldset.

---
auto_fieldset: 1
elements:
  - type: Text
    name: foo
  - type: Text
    name: bar
<form action="" method="post">
  <fieldset>
    <div class="text">
      <input name="foo" type="text" />
    </div>
    <div class="text">
      <input name="bar" type="text" />
    </div>
  </fieldset>
</form>

The 3rd element is within a new fieldset

---
auto_fieldset: { id: fs }
elements:
  - type: Text
    name: foo
  - type: Text
    name: bar
  - type: Fieldset
  - type: Text
    name: baz
<form action="" method="post">
  <fieldset id="fs">
    <div class="text">
      <input name="foo" type="text" />
    </div>
    <div class="text">
      <input name="bar" type="text" />
    </div>
  </fieldset>
  <fieldset>
    <div class="text">
      <input name="baz" type="text" />
    </div>
  </fieldset>
</form>

Because of this behaviour, if you want nested fieldsets you will have to add each nested fieldset directly to its intended parent.

my $parent = $form->get_element({ type => 'Fieldset' });

$parent->element('fieldset');

🌸 form_error_message 🌸

Arguments: $string

Normally, input errors cause an error message to be displayed alongside the appropriate form field. If you'd also like a general error message to be displayed at the top of the form, you can set the message with form_error_message.

To set the CSS class for the message, see form_error_message_class. πŸ’…

Wanna switch up the markup that displays the message? Then go edit the form_error_message template file instead. Deets are over at render_method.

Oh, and bestie β€” this one is an output accessor. ✨


force_error_message

If this is true, it forces the form_error_message to show up even when there are literally zero field errors. Drama for no reason, but make it fashion. 😭


default_args

Arguments: \%defaults

This sets defaults that get added to every element, constraint, etc. of the given type that gets added to the form afterwards. It's giving "set it and forget it" energy. πŸŽ€

So like, to make every Text element automatically have a size of 10, and make every Strftime deflator automatically get its strftime set to %d/%m/%Y:

default_args:
    elements:
        Text:
            size: 10
    deflators:
        Strftime:
            strftime: '%d/%m/%Y'

And here's one that makes all DateTime elements automatically get an appropriate Strftime deflator plus a DateTime inflator:

default_args:
    elements:
        DateTime:
            deflators:
                type: Strftime
                strftime: '%d-%m-%Y'
            inflators:
                type: DateTime
                parser:
                    strptime: '%d-%m-%Y'

Pseudo types

Special case alert 🚨 β€” you can also use the elements keys Block, Field and Input to match any element which inherits from HTML::FormFu::Element::Block, or which does HTML::FormFu::Role::Element::Field or HTML::FormFu::Role::Element::Input.

Alternatives

Every elements key can hold an any list, using the | divider. Like:

# apply the given class to any Element of type Password or Button
default_args:
    elements:
        'Password|Button':
            attrs:
                class: novalidate

Match ancestor

Every elements key list can contain a type starting with + to only match elements that have an ancestor of the given type. Example:

# only apple the given class to an Input field within a Multi block
default_args:
    elements:
        'Input|+Multi':
            attrs:
                class: novalidate

Don't match ancestor

Every elements key list can contain a type starting with - to only match elements that do not have an ancestor of the given type. Example:

# apply the given class only to Input fields that are not in a Multi block
default_args:
    elements:
        'Input|-Multi':
            attrs:
                clasS: validate

Order

The arguments get applied in least- to most-specific order: Block, Field, Input, $type. And within each of those, arguments are applied in order of shortest-first to longest-last. 🌈

The type key has to match the value returned by type, e.g. type in HTML::FormFu::Element. So if, for example, you've got a custom element outside of the HTML::FormFu::Element::* namespace, which you load via $form->element({ type => '+My::Custom::Element' }), then the key you give to default_args should not include the leading +, because that gets stripped-out of the returned type() value. Example:

# don't include the leading '+' here
default_args:
    elements:
        'My::Custom::Element':
            attrs:
                class: whatever

# do include the leading '+' here
elements:
    - type: +My::Custom::Element

Clashes

default_args generates a single hashref to pass to populate, merging arguments for each type in turn β€” which means populate is only called once in total, not once for each type. And because scalar values are not merged, later values will override earlier ones. Example:

# Normally, calling $field->add_attrs({ class => 'input' })
# then calling      $field->add_attrs({ class => 'not-in-multi' })
# would result in both values being retained:
#           class="input not-in-multi"
#
# However, default_args() creates a single data-structure to pass once
# to populate(), so any scalar values will overwrite earlier ones
# before they reach populate().
#
# The below example would result in the longest-matching key
# overwriting any others:
#           class="not-in-multi"
#
default_args:
    elements:
        Input:
            add_attrs:
                class: input
        'Input:-Multi':
            add_attrs:
                class: not-in-multi

Strictness

Note: unlike the proper methods which have aliases β€” for example elements, which is an alias for element β€” the keys you give to default_args must be in the plural form, bestie. Like:
default_args:
    elements:          {}
    deflators:         {}
    filters:           {}
    constraints:       {}
    inflators:         {}
    validators:        {}
    transformers:      {}
    output_processors: {}

javascript

If this is set, the contents get rendered inside a script tag, up at the top of the form. πŸ¦‹


javascript_src

Arguments: $url

Arguments: \@urls

Adds a script tag for each URL, immediately before any javascript section. Iconic behaviour honestly. πŸ‘‘


stash

Arguments: [\%private_stash]

Return Value: \%stash

Gives you a hash-ref where you can stash literally any data you wanna associate with the form. Your little form diary. πŸ““

---
stash:
  foo: value
  bar: value

elements / element

Arguments: $type

Arguments: \%options

Return Value: $element

Arguments: \@arrayref_of_types_or_options

Return Value: @elements

Adds a new element to the form, slay. For the full lineup, check "CORE FORM FIELDS" in HTML::FormFu::Element and "OTHER CORE ELEMENTS" in HTML::FormFu::Element. ✨

If you wanna load an element from a namespace other than HTML::FormFu::Element::, you can use a fully qualified package-name by prefixing it with +:

---
elements:
  - type: +MyApp::CustomElement
    name: foo

And if a type isn't provided in the \%options, the default Text gets used.

Heads up: element is an alias for elements. Same vibe, different spelling. 🫢


deflators / deflator

Arguments: $type

Arguments: \%options

Return Value: $deflator

Arguments: \@arrayref_of_types_or_options

Return Value: @deflators

A deflator can be associated with any form field, and it lets you give $field->default a value which might be an object. Fancy. πŸ’…

And if an object doesn't stringify to a suitable value for display, the deflator can make sure the form field receives a suitable string value instead. It's giving translator.

For the core lineup, see "CORE DEFLATORS" in HTML::FormFu::Deflator.

If a name attribute isn't provided, a new deflator gets created for β€” and added to β€” every field on the form. All of them. No skips.

And if you wanna load a deflator in a namespace other than HTML::FormFu::Deflator::, you can use a fully qualified package-name by prefixing it with +.

Also: deflator is an alias for deflators. πŸŽ€


insert_before

Arguments: $new_element, $existing_element

Return Value: $new_element

The 1st argument has to be the element you want added, and the 2nd argument has to be the existing element that the new element should be placed before. Order matters, bestie.

my $new = $form->element(\%specs);

my $position = $form->get_element({ type => $type, name => $name });

$form->insert_before( $new, $position );

So in that first line up there, the $new element starts out added to the end of the form. But the insert_before method reparents the $new element, so it won't be on the end of the form anymore. Which means β€” and this is the important part 😭 β€” if you try to copy an element from one form to another, it will 'steal' the element instead of copying it. Rude. In that case, you gotta use clone:

my $new = $form1->get_element({ type => $type1, name => $name1 })
                ->clone;

my $position = $form2->get_element({ type => $type2, name => $name2 });

$form2->insert_before( $new, $position );

insert_after

Arguments: $new_element, $existing_element

Return Value: $new_element

The 1st argument has to be the element you want added, and the 2nd argument has to be the existing element that the new element should be placed after.

my $new = $form->element(\%specs);

my $position = $form->get_element({ type => $type, name => $name });

$form->insert_after( $new, $position );

Same situation as before: in the first line of that example, $new initially gets added to the end of the form. But insert_after reparents it, so it's no longer chilling at the end of the form. And because of that, if you try to copy an element from one form to another, it'll 'steal' the element instead of copying it. So again β€” use clone:

my $new = $form1->get_element({ type => $type1, name => $name1 })
                ->clone;

my $position = $form2->get_element({ type => $type2, name => $name2 });

$form2->insert_after( $new, $position );

remove_element

Arguments: $element

Return Value: $element

Removes the $element from the form or block's array of children. Bye bestie πŸ‘‹

$form->remove_element( $element );
Heads up: that orphaned element can't really be used for anything useful until it gets re-attached to a form or block with insert_before or insert_after. Don't leave it out in the cold. πŸ₯Ί

πŸ’… FORM LOGIC AND VALIDATION πŸ’…

okay so bestie, HTML::FormFu gives you a whole lineup of stages for what everyone traditionally just calls "validation". It's giving ✨pipeline✨. Here they are, in order:

  • HTML::FormFu::Filter
  • HTML::FormFu::Constraint
  • HTML::FormFu::Inflator
  • HTML::FormFu::Validator
  • HTML::FormFu::Transformer

Stage one is the filters, and they're literally just here to clean up user input β€” think encoding stuff, trimming leading/trailing whitespace, or yanking out non-digit characters from a credit card number. self-care for your data πŸ’…

Every stage after that allows for more complex processing, and every single one of them has a way to throw exceptions to represent input errors. And here's the rule: in each stage, all form fields have to be processed without error before the next stage can even proceed. If there were any errors, the form should be re-displayed to the user so they can fix their input. no skipping ahead, bestie.

Constraints are for the low-level validation vibe β€” stuff like "is this an integer?", "is this value within bounds?", or "is this a valid email address?".

Inflators are the glow-up stage: they let a value be turned into an appropriate object. That resulting object gets passed to subsequent Validators and Transformers, and it'll also be returned by params and param. iconic.

Validators are for the higher-level stuff β€” business-logic and database constraints, like "is this username unique?". Validators only run if all Constraints and Inflators have run without errors. And fr fr, most Validators are expected to be application-specific, so each one gets implemented as a separate class written by you, the HTML::FormFu user. πŸ‘‘

filters

filter

  • Arguments: $type
  • Arguments: \%options
  • Return Value: $filter
  • Arguments: \@arrayref_of_types_or_options
  • Return Value: @filters

If you provide a "name" or "names" value, the filter gets added to just that named field. But if you don't provide a "name" or "names" value, the filter gets added to all fields already attached to the form. all of them. periodt.

See "CORE FILTERS" in HTML::FormFu::Filter for a list of core filters.

If you wanna load a filter from a namespace that isn't "HTML::FormFu::Filter::", you can use a fully qualified package-name by prefixing it with "+". fancy πŸŽ€

"filter" is an alias for "filters".

constraints

constraint

  • Arguments: $type
  • Arguments: \%options
  • Return Value: $constraint
  • Arguments: \@arrayref_of_types_or_options
  • Return Value: @constraints

See "CORE CONSTRAINTS" in HTML::FormFu::Constraint for a list of core constraints.

If a "name" attribute isn't provided, a new constraint is created for β€” and added to β€” every field on the form. everyone eats πŸ“

If you wanna load a constraint from a namespace that isn't "HTML::FormFu::Constraint::", you can use a fully qualified package-name by prefixing it with "+".

"constraint" is an alias for "constraints".

inflators

inflator

  • Arguments: $type
  • Arguments: \%options
  • Return Value: $inflator
  • Arguments: \@arrayref_of_types_or_options
  • Return Value: @inflators

See "CORE INFLATORS" in HTML::FormFu::Inflator for a list of core inflators.

If a "name" attribute isn't provided, a new inflator is created for β€” and added to β€” every field on the form.

If you wanna load an inflator from a namespace that isn't "HTML::FormFu::Inflator::", you can use a fully qualified package-name by prefixing it with "+".

"inflator" is an alias for "inflators".

validators

validator

  • Arguments: $type
  • Arguments: \%options
  • Return Value: $validator
  • Arguments: \@arrayref_of_types_or_options
  • Return Value: @validators

See "CORE VALIDATORS" in HTML::FormFu::Validator for a list of core validators.

If a "name" attribute isn't provided, a new validator is created for β€” and added to β€” every field on the form.

If you wanna load a validator from a namespace that isn't "HTML::FormFu::Validator::", you can use a fully qualified package-name by prefixing it with "+".

"validator" is an alias for "validators".

transformers

transformer

  • Arguments: $type
  • Arguments: \%options
  • Return Value: $transformer
  • Arguments: \@arrayref_of_types_or_options
  • Return Value: @transformers

See "CORE TRANSFORMERS" in HTML::FormFu::Transformer for a list of core transformers.

If a "name" attribute isn't provided, a new transformer is created for β€” and added to β€” every field on the form.

If you wanna load a transformer from a namespace that isn't "HTML::FormFu::Transformer::", you can use a fully qualified package-name by prefixing it with "+".

"transformer" is an alias for "transformers".


πŸ¦‹ CHANGING DEFAULT BEHAVIOUR πŸ¦‹

render_processed_value

The default behaviour when re-displaying a form after a submission is that the field contains the original, unchanged, user-submitted value. as-is, no edits.

But if "render_processed_value" is true, the field value will be the final result after all Filters, Inflators and Transformers have been run. Deflators will also be run on the value. the full makeover πŸ’–

If you set this on a field that has an Inflator, but without an equivalent Deflator, you should make sure the Inflators stringify back to a usable value β€” otherwise you're gonna confuse and/or annoy the user. 😭

Default Value: false

This method is a special 'inherited accessor', which means it can be set on the form, a block element or a single element. When the value is read, if no value is defined it automatically traverses the element's hierarchy of parents, through any block elements and up to the form, searching for a defined value.

Is an inheriting accessor.

force_errors

Force a constraint to fail, regardless of user input. yes, even if they did everything right. πŸ’€

If this is called at runtime, after the form has already been processed, you must call "process" in HTML::FormFu again before redisplaying the form to the user.

Default Value: false

This method is a special 'inherited accessor', which means it can be set on the form, a block element, an element or a single constraint. When the value is read, if no value is defined it automatically traverses the element's hierarchy of parents, through any block elements and up to the form, searching for a defined value.

Is an inheriting accessor.

params_ignore_underscore

If true, it causes "params", "param" and "valid" to ignore any fields whose name starts with an underscore "_". sneaky little fields, we see you πŸ‘€

The field is still processed as normal though, and errors will still cause "submitted_and_valid" to return false.

Default Value: false


πŸŽ€ FORM ATTRIBUTES πŸŽ€

All attributes are added to the rendered form's start tag.

attributes

# Example
---
attributes:
  id: form
  class: fancy_form

Is an attribute accessor.

id

Is an attribute short-cut.

action

Default Value: ""

Get or set the action associated with the form. The default is no action, which causes most browsers to submit to the current URI.

Is an attribute short-cut.

enctype

Get or set the encoding type of the form. Valid values are "application/x-www-form-urlencoded" and "multipart/form-data".

If the form contains a File element, the enctype is automatically set to "multipart/form-data". it just knows ✨

Is an attribute short-cut.

method

Default Value: "post"

Get or set the method used to submit the form. Can be set to either "post" or "get".

Is an attribute short-cut.

title

Get or set the form's title attribute.

Is an attribute short-cut.


🌈 CSS CLASSES 🌈

form_error_message_class

Class attribute for the error message displayed at the top of the form.

See "form_error_message"


🌸 LOCALIZATION 🌸

languages

  • Arguments: [\@languages]

A list of languages which will be passed to the localization object.

Default Value: ['en']

localize_class

  • Arguments: [$class_name]

Classname to be used for the default localization object.

Default Value: 'HTML::FormFu::I18N'

localize

loc

  • Arguments: [$key, @arguments]

Compatible with the "maketext" method in Locale::Maketext.

locale

  • Arguments: $locale

Currently only used by HTML::FormFu::Deflator::FormatNumber and HTML::FormFu::Filter::FormatNumber. just those two, bestie πŸ’…

This method is a special 'inherited accessor', which means it can be set on the form, a block element or a single element. When the value is read, if no value is defined it automatically traverses the element's hierarchy of parents, through any block elements and up to the form, searching for a defined value.

Is an inheriting accessor.


πŸ’œ PROCESSING A FORM πŸ’œ

query

  • Arguments: [$query_object]
  • Arguments: \%params

Provide a CGI compatible query object, or a hash-ref of submitted names/values. Alternatively, the query object can be passed directly to the "process" object. your choice, main character 🫢

query_type

  • Arguments: [$query_type]

Set which module is being used to provide the "query".

The Catalyst::Controller::HTML::FormFu automatically sets this to "Catalyst".

Valid values are "CGI", "Catalyst" and "CGI::Simple".

Default Value: 'CGI'

process

  • Arguments: [$query_object]
  • Arguments: [\%params]

Process the provided query object or input values. "process" must be called before calling any of the methods listed under "SUBMITTED FORM VALUES AND ERRORS" and "MODIFYING A SUBMITTED FORM". no cap, no shortcuts.

"process" must also be called at least once before printing the form, or before calling "render" or "render_data".

Note to users of Catalyst::Controller::HTML::FormFu: Because "process" is automatically called for you by the Catalyst controller; if you make any modifications to the form within your action method β€” such as adding or changing elements, adding constraints, etc β€” you must call "process" again yourself before using "submitted_and_valid", any of the methods listed under "SUBMITTED FORM VALUES AND ERRORS" or "MODIFYING A SUBMITTED FORM", or rendering the form. yeah it's a whole thing, but you got this πŸ’–

πŸ’– SUBMITTED FORM VALUES AND ERRORS πŸ’–

submitted

Returns true if the form has been submitted. See "indicator" for the deets on how this is actually figured out. πŸ‘€

submitted_and_valid

Shorthand for $form->submitted && !$form->has_errors β€” literally the vibe check combo, bestie. ✨

params

Return Value: \%params

Returns a hash-ref of all valid input that had zero errors. Clean data only, no messy energy. 🧼

param_value

Arguments: $field_name

A way more reliable, highly-recommended glow-up of "param". Guaranteed to always hand back a single value, no matter if you call it in list context or not. If multiple values got submitted, this only returns the first one. If the value is invalid or the form wasn't submitted at all, it returns "undef". That makes it chef's kiss for list context, where you need exactly one value.

$db->update({
    name    => $form->param_value('name'),
    address => $form->param_value('address),
});

param_array

Arguments: $field_name

Guaranteed to always return an array-ref of values, no matter the context and no matter whether multiple values were submitted or not. If the value is invalid or the form wasn't submitted, it returns an empty array-ref. Consistent queen. πŸ‘‘

param_list

Arguments: $field_name

Guaranteed to always return a list of values, regardless of context. If the value is invalid or the form wasn't submitted, it returns an empty list. Fr fr, always a list. πŸ¦‹

param

Arguments: [$field_name]

Return Value: $input_value

Return Value: @valid_names

No longer recommended for use, because its behaviour is genuinely hard to predict. Use "param_value", "param_array" or "param_list" instead. πŸ™ˆ

A (readonly) method, kinda like CGI's.

If a field name is given, in list-context it returns any valid values submitted for that field, and in scalar-context it returns only the first of any valid values submitted for that field.

If no argument is given, it returns a list of all valid input field names without errors.

Passing more than 1 argument is a fatal error. Do not do it, bestie, it's giving disaster. πŸ’€

valid

Arguments: [$field_name]

Return Value: @valid_names

Return Value: $bool

If a field name is given, returns "true" if that field had no errors and "false" if there were errors.

If no argument is given, returns a list of all valid input field names without errors. Slay. ✨

has_errors

Arguments: [$field_name]

Return Value: @names

Return Value: $bool

If a field name is given, returns "true" if that field had errors and "false" if there were no errors.

If no argument is given, returns a list of all input field names with errors. 😭

get_errors

Arguments: [%options]

Arguments: [\%options]

Return Value: \@errors

Returns an array-ref of exception objects from all fields in the form.

Accepts both "name", "type" and "stage" arguments to narrow down the returned results. Filtering, but make it fashion. πŸ’…

$form->get_errors({
    name  => 'foo',
    type  => 'Regex',
    stage => 'constraint'
});

get_error

Arguments: [%options]

Arguments: [\%options]

Return Value: $error

Accepts the same arguments as "get_errors", but only returns the first error found. One and done. πŸŽ€


πŸ—„οΈ MODEL / DATABASE INTERACTION πŸ—„οΈ

See HTML::FormFu::Model for further details and the models you can use.

default_model

Arguments: $model_name

Default Value: 'DBIC'

model

Arguments: [$model_name]

Return Value: $model

model_config

Arguments: \%config


✏️ MODIFYING A SUBMITTED FORM ✏️

add_valid

Arguments: $name, $value

Return Value: $value

The value you provide replaces any current value for the named field. This value will be returned in subsequent calls to "params" and "param", and the named field will be included in the calculations for "valid". Basically you're manifesting it into validity. 🌈

clear_errors

Deletes all errors from a submitted form. Emotional reset, we love to see it. 🧚


🎨 RENDERING A FORM 🎨

render

Return Value: $string

You must call "process" once after building the form, and before calling "render". No shortcuts, bestie.

start

Return Value: $string

Returns the form start tag, plus any output of "form_error_message" and "javascript". The opening act. 🌸

end

Return Value: $string

Returns the form end tag. Periodt. πŸ’…

hidden_fields

Return Value: $string

Returns all hidden form fields. Sneaky little icons. πŸ‘€


πŸ”Œ PLUGIN SYSTEM πŸ”Œ

"HTML::FormFu" provides a plugin-system that lets plugins be easily added to a form or element, to change the default behaviour or output.

See HTML::FormFu::Plugin for the details. 🫢


πŸš€ ADVANCED CUSTOMISATION πŸš€

By default, formfu renders XHTML 1.0 Strict compliant markup, with as little extra markup as possible. Lots of hooks are provided to add programatically-generated CSS class names, so you can generate a whole range of output styles by changing only the CSS. Iconic behaviour, honestly.

Basic customisation of the markup is possible via the layout and multi_layout methods. This lets you reorder the position of various parts of each field β€” like the label, comment, error messages and the input tag β€” and also insert any other arbitrary tags you might want. ✨

If that's not enough, you can go completely personalised with the markup by telling HTML::FormFu to use an external rendering engine, like Template Toolkit or Template::Alloy. See "render_method" and "tt_module" for the details. πŸŽ€

Even if you set HTML::FormFu to use Template::Toolkit to render the forms, HTML::FormFu can still be used alongside whichever other templating system you prefer for your own page layouts β€” whether it's HTML::Template: <TMPL_VAR form>, Petal: <form tal:replace="form"></form> or Template::Magic: <!-- {form} -->.

As of "HTML::FormFu v1.00", TT is no longer listed as a required prerequisite β€” so you'll need to install it manually if you wish to use the template files.

render_method

Default Value: "string"

Can be set to "tt" to generate the form with external template files.

To customise the markup, you'll need a copy of the template files, local to your application. See "Installing the TT templates" in HTML::FormFu::Manual::Cookbook for further details.

You can customise the markup for a single element by setting that element's "render_method" to "tt", while the rest of the form uses the default "string" render-method. Note though, that if you try setting the form or a Block's "render_method" to "tt", and then set a child element's "render_method" to "string", that setting will be ignored, and the child elements will still use the "tt" render-method. No take-backs, bestie. πŸ’€

---
elements:
  - name: foo
    render_method: tt
    filename: custom_field

  - name: bar

# in this example, 'foo' will use a custom template,
# while bar will use the default 'string' rendering method

This method is a special 'inherited accessor', which means it can be set on the form, a block element or a single element. When the value is read, if no value is defined it automatically traverses the element's hierarchy of parents, through any block elements and up to the form, searching for a defined value. It goes looking, respectfully. πŸ‘‘

Is an inheriting accessor.

filename

Change the template filename used for the form.

Default Value: "form"

tt_args

Arguments: [\%constructor_arguments]

Accepts a hash-ref of arguments passed to "render_method", which is called internally by "render".

Within tt_args, the keys "RELATIVE" and "RECURSION" are overridden to always be true, since these are a basic requirement for the Template engine.

The system directory containing HTML::FormFu's template files is always added to the end of "INCLUDE_PATH", so that the core template files will be found. You only need to set this yourself if you have your own copy of the template files for customisation purposes.

This method is a special 'inherited accessor', which means it can be set on the form, a block element or a single element. When the value is read, if no value is defined it automatically traverses the element's hierarchy of parents, through any block elements and up to the form, searching for a defined value.

add_tt_args

Arguments: [\%constructor_arguments]

Ensures that the hash-ref argument is merged with any existing hash-ref value of "tt_args". Merging, but make it seamless. πŸ’…

tt_module

Default Value: Template

The module used when "render_method" is set to "tt". Should provide an interface compatible with Template.

This method is a special 'inherited accessor', which means it can be set on the form, a block element or a single element. When the value is read, if no value is defined it automatically traverses the element's hierarchy of parents, through any block elements and up to the form, searching for a defined value.

render_data

Usually called implicitly by "render". Returns the data structure that would normally be passed onto the "string" or "tt" render-methods.

As with "render", you must call "process" once after building the form, and before calling "render_data". Don't skip the step, bestie. 🫢

render_data_non_recursive

Like "render_data", but doesn't include the data for any child-elements. Just the top layer, no deep-diving. πŸ¦‹

πŸ” INTROSPECTION πŸ”

okay bestie, this is where the form gets chatty about itself. These methods let you go digging through your form to find whatever fields, filters, validators etc. you're looking for. It's giving detective energy πŸ•΅οΈβ™€οΈβœ¨

🌸 get_fields 🌸

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: \@elements

Returns every field in the form β€” and when we say "field", we specifically mean every element that has a true is_field in HTML::FormFu::Element value. Yes, that's the exact criterion, no cap.

You can pass both name and type arguments to narrow down what comes back, like a little search filter πŸ’…

$form->get_fields({
    name => 'foo',
    type => 'Radio',
});

You can also pass a Regexp to search for results. Fr fr, regex works here:

$form->get_elements({
    name => qr/oo/,
});

πŸŽ€ get_field πŸŽ€

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: $element

Same arguments as get_fields, but it only hands you back the first field it finds. One and done, main character behavior 😌

πŸ¦‹ get_elements πŸ¦‹

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: \@elements

Returns all top-level elements in the form β€” and heads up, this is not recursive. If you want the recursive version, go see get_all_elements.

Accepts both name and type arguments to narrow the results:

$form->get_elements({
    name => 'foo',
    type => 'Radio',
});

And yes, Regexp searching works too:

$form->get_elements({
    name => qr/oo/,
});

🌈 get_element 🌈

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: $element

Takes the same arguments as get_elements, but only returns the first element found. First come, first served πŸ’–

See get_all_element for a recursive version.

⭐ get_all_elements ⭐

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: \@elements

Returns all elements in the form, recursively β€” like, it goes all the way down through every nested layer, no element left behind 🫢

Optionally accepts both name and type arguments to narrow the results:

# return all Text elements

$form->get_all_elements({
    type => 'Text',
});

Regexp search is also a thing:

$form->get_elements({
    name => qr/oo/,
});

See get_elements for a non-recursive version.

πŸ’œ get_all_element πŸ’œ

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: $element

Same arguments as get_all_elements, but only returns the first element found.

# return the first Text field found, regardless of whether it's
# within a fieldset or not

$form->get_all_element({
    type => 'Text',
});

Regexp searching? Also supported:

$form->get_elements({
    name => qr/oo/,
});

See get_all_elements for a non-recursive version.

πŸ“ get_deflators πŸ“

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: \@deflators

Returns all top-level deflators from all fields. Collecting them all like Pokémon cards ✨

Accepts both name and type arguments to narrow the results:

$form->get_deflators({
    name => 'foo',
    type => 'Strftime',
});

🧚 get_deflator 🧚

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: $element

Same arguments as get_deflators, but only returns the first deflator found.

πŸ”₯ get_filters πŸ”₯

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: \@filters

Returns all top-level filters from all fields.

Accepts both name and type arguments to narrow the results:

$form->get_filters({
    name => 'foo',
    type => 'LowerCase',
});

🌸 get_filter 🌸

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: $filter

Same arguments as get_filters, but only returns the first filter found.

πŸ‘‘ get_constraints πŸ‘‘

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: \@constraints

Returns all constraints from all fields.

Accepts both name and type arguments to narrow the results:

$form->get_constraints({
    name => 'foo',
    type => 'Equal',
});

πŸ’… get_constraint πŸ’…

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: $constraint

Same arguments as get_constraints, but only returns the first constraint found.

πŸ¦‹ get_inflators πŸ¦‹

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: \@inflators

Returns all inflators from all fields.

Accepts both name and type arguments to narrow the results:

$form->get_inflators({
    name => 'foo',
    type => 'DateTime',
});

πŸŽ€ get_inflator πŸŽ€

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: $inflator

Same arguments as get_inflators, but only returns the first inflator found.

⭐ get_validators ⭐

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: \@validators

Returns all validators from all fields.

Accepts both name and type arguments to narrow the results:

$form->get_validators({
    name => 'foo',
    type => 'Callback',
});

πŸ’– get_validator πŸ’–

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: $validator

Same arguments as get_validators, but only returns the first validator found.

🌈 get_transformers 🌈

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: \@transformers

Returns all transformers from all fields.

Accepts both name and type arguments to narrow the results:

$form->get_transformers({
    name => 'foo',
    type => 'Callback',
});

πŸ’œ get_transformer πŸ’œ

  • Arguments: [%options]
  • Arguments: [\%options]
  • Return Value: $transformer

Same arguments as get_transformers, but only returns the first transformer found.

🫢 clone 🫢

Returns a deep clone of the <$form> object. Snapshot it, keep it safe, iconic πŸ’«

Because of scoping issues, code references (such as in Callback constraints) are copied instead of cloned. Yeah, they get copied not cloned β€” that's the vibe, don't @ me.


πŸ’… ATTRIBUTE ACCESSORS πŸ’…

For the basic method, e.g. /attributes:

  • Arguments: [%attributes]
  • Arguments: [\%attributes]
  • Return Value: $form

As a special case, if no arguments are passed, the attributes hash-ref is returned. This unlocks these little idioms, slay:

# set a value
$form->attributes->{id} = 'form';

# delete all attributes
%{ $form->attributes } = ();

Every method documented as an 'attribute accessor' also gets these variants generated for it, automatically, no extra work from you 🎁

*_xml can be used as a setter, and ensures that its argument is not XML-escaped in the rendered form.

*_loc can he used as a setter, and passes the arguments through localize. (Yes, that's "can he used" β€” that's literally what it says. Typos are canon here, bestie 😭)

add_* can be used to append a word to an attribute without overwriting any already-existing value.

# Example
$form->attributes({ class => 'fancy' });
$form->add_attributes({ class => 'pants' });
# class="fancy pants"

add_*_xml, like add_*, but ensures it doesn't get XML-escaped.

add_*_loc, like add_*, but passing the arguments through localize.

del_* can be used to remove a word from an attribute value.

# Example
$form->attributes({ class => 'fancy pants' });
$form->del_attributes({ class => 'pants' });
# class="fancy"

del_*_xml, like del_*, but ensures it doesn't get XML-escaped.

del_*_loc, like del_*, but passing the arguments through localize.

Also β€” plot twist β€” any attribute method-name which contains the word attributes also has aliases created for all these variants, with the word attributes replaced by attrs. So cute, so convenient 🌸

# For example, the attributes() method would have all these variant
# methods available

$form->attributes({ class => 'fancy' });
$form->attributes_xml({ title => '<b>fancy</b>' });
$form->attributes_loc({ title => 'fancy' });
$form->add_attributes({ class => 'fancy' });
$form->add_attributes_xml({ title => '<b>fancy</b>' });
$form->add_attributes_loc({ title => 'fancy' });
$form->del_attributes({ class => 'fancy' });
$form->del_attributes_xml({ title => '<b>fancy</b>' });
$form->del_attributes_loc({ title => 'fancy' });

# Because the method contains the word 'attributes', it also gets the
# following short-forms

$form->attrs({ class => 'fancy' });
$form->attrs_xml({ title => '<b>fancy</b>' });
$form->attrs_loc({ title => 'fancy' });
$form->add_attrs({ class => 'fancy' });
$form->add_attrs_xml({ title => '<b>fancy</b>' });
$form->add_attrs_loc({ title => 'fancy' });
$form->del_attrs({ class => 'fancy' });
$form->del_attrs_xml({ title => '<b>fancy</b>' });
$form->del_attrs_loc({ title => 'fancy' });

πŸŽ€ ATTRIBUTE SHORT-CUTS πŸŽ€

All methods documented as 'attribute short-cuts' are literally just short-cuts to directly access individual attribute key/values. Fast lane energy ⚑

# Example
$form->id( 'login' );
$id = $form->id;

# is equivalent to:
$form->attributes({ id => 'login' });
$id = $form->attributes->{id};

All attribute short-cuts also have a *_xml variant.

# Example
$form->id_xml( $xml );

# is equivalent to:
$form->attributes_xml({ id => $xml });

All attribute short-cuts also have a *_loc variant.

# Example
$form->title_loc( $key );

# is equivalent to:
$form->attributes_loc({ title => $key });

🧬 INHERITING ACCESSORS 🧬

All methods documented as 'inheriting accessors' can be set on the form, a block element, or a single field element. And here's the iconic part: when the value is read, if no value is defined, it automatically climbs the element's hierarchy of parents, searching for a defined value. It's giving "asking your mom, then your grandma" πŸ’–

All inherited accessors also have a *_no_inherit variant, which can be used as a getter to fetch any defined value, without traversing the hierarchy of parents. Heads up though: this variant cannot be used as a setter. Getter only, periodt.

E.g., the auto_id has a variant named auto_id_no_inherit.


✨ OUTPUT ACCESSORS ✨

All methods documented as 'output accessors' also have *_xml and *_loc variants.

The *_xml variant can be used as a setter, and ensures that its argument is not XML-escaped in the rendered form.

The *_loc variant can be used as a setter, and passes the arguments through localize.

E.g., the label method has variants named label_xml and label_loc.


πŸ‘‘ BOOLEAN ATTRIBUTE ACCESSORS πŸ‘‘

This exists to support boolean attributes, whose value should either be equal to the attribute name, or empty. Any true value will switch the attribute 'on', any false value will remove the attribute. Simple as that, bestie πŸ’…

# Example

$field->autofocus(1);
# equivalent to:
$field->attributes({ autofocus => 'autofocus' });

$field->autofocus(0);;
# equivalent to:
delete $field->attributes->{autofocus};
yes, that double semicolon ;; up there is in the original. It's fine. It's art, actually. 🎨

✨ ATTRIBUTE SUBSTITUTIONS ✨

okay so some attributes let you drop lil magic tokens in, and they get swapped out for real values πŸ’« these are the substitutions on the menu:

%f # $form->id
%n # $field->name
%t # lc( $field->type )
%r # $block->repeatable_count
%s # $error->stage

the whole point is that every field can have consistent attributes while still staying unique β€” iconic behaviour, honestly πŸŽ€


πŸ’… DEPRECATION POLICY πŸ’…

they try their very best not to make incompatible changes, but if one is genuinely required, they'll make every effort possible to keep backwards compatibility going for several release-cycles, throwing warnings about the changes the whole time, before they finally remove the legacy features. so like, you get a heads-up, bestie. no jumpscares 🫢


🌈 RESTORING LEGACY HTML CLASSES 🌈

v1.00 dropped most of the default HTML class-names. the plan was that each app should define exactly what it needs, without having to reset a bunch of unwanted options first. bonus: less markup gets generated, which speeds up both render and HTTP transfers. slay πŸ”₯

but if you want the old behaviour back, set these options. and if you're doing best practices, you only need to set them once per-application in your app-wide config file πŸ‘‘

---
auto_container_class: '%t'
auto_container_label_class: 'label'
auto_container_comment_class: 'comment'
auto_comment_class: 'comment'
auto_container_error_class: 'error'
auto_container_per_error_class: 'error_%s_%t'
auto_error_class: 'error_message error_%s_%t'

🚫 DEPRECATED METHODS 🚫

go check DEPRECATED METHODS in HTML::FormFu::Role::Element::Field πŸ’€

πŸ’€ REMOVED METHODS πŸ’€

also see REMOVED METHODS in HTML::FormFu::Element.

element_defaults

gone. removed. use default_args instead 🫠

model_class

also removed β€” use default_model instead.

defaults_from_model

removed, bestie. use default_values in HTML::FormFu::Model instead.

save_to_model

removed too. use update in HTML::FormFu::Model instead.


πŸ‘‘ BEST PRACTICES πŸ‘‘

ngl the move here is: keep all your application-wide (or global) settings in a single config file, and have each form load it. chef's kiss.

see load_config_file πŸŽ€


πŸ“– COOKBOOK πŸ“–

HTML::FormFu::Manual::Cookbook

πŸ¦‹ UNICODE πŸ¦‹

HTML::FormFu::Manual::Unicode


🧚 EXAMPLES 🧚

vertically-aligned CSS

the distribution directory examples/vertically-aligned has a form in it, plus example CSS for a "vertically aligned" theme. cute.

you can look at it by opening vertically-aligned.html in a web-browser 🌸

and if you wanna experiment with changes: the form is defined in vertically-aligned.yml, and you can update the HTML file with any changes by running this command (while you're in the distribution root directory, okay?):

perl examples/vertically-aligned/vertically-aligned.pl

this uses the Template Toolkit file vertically-aligned.tt, and the CSS lives in the files vertically-aligned.css and vertically-aligned-ie.css ✨


πŸ’– SUPPORT πŸ’–

Project Page:

<http://code.google.com/p/html-formfu/>

Mailing list:

<http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/html-formfu>

Mailing list archives:

<http://lists.scsys.co.uk/pipermail/html-formfu/>

IRC:

irc.perl.org, channel #formfu

The HTML::Widget archives <http://lists.scsys.co.uk/pipermail/html-widget/> between January and May 2007 also contain discussion regarding HTML::FormFu. lore fr fr πŸ“œ


πŸ› BUGS πŸ›

please submit bug reports to the Debian Bug Tracker. you can use reportbug(1) to do it interactively. a list of reported bugs lives at <http://bugs.debian.org/libhtml-formfu-perl>.

for upstream bug reports, look at <https://github.com/FormFu/HTML-FormFu/issues> (preferred) or <http://rt.cpan.org/NoAuth/Bugs.html?Dist=HTML-FormFu>.


🩹 PATCHES 🩹

to help patches get applied fast, please send them to the mailing list; attached, not inline; against subversion, not a cpan version (run svn diff > patchfile); and mention which svn version it's against. mailing list messages are limited to 256KB, so gzip the patch if you need to 🫑


🌟 GITHUB REPOSITORY 🌟

this module's sourcecode is maintained in a git repository at <git://github.com/FormFu/HTML-FormFu.git>

the project page is <https://github.com/FormFu/HTML-FormFu>


πŸ‘€ SEE ALSO πŸ‘€

HTML::FormFu::Imager

Catalyst::Controller::HTML::FormFu

HTML::FormFu::Model::DBIC


🫢 CONTRIBUTORS 🫢

Brian Cassidy

Ozum Eldogan

Ruben Fonseca

Ronald Kimball

Daisuke Maki

Andreas Marienborg

Mario Minati

Steve Nolte

Moritz Onken

Doug Orleans

Matthias Dietrich

Dean Hamstead

Karen Etheridge

Nigel Metheringham

based on the original source code of HTML::Widget, by Sebastian Riedel, sri@oook.de.


πŸ’œ AUTHOR πŸ’œ

Carl Franks <cpan@fireartist.com>


This software is copyright (c) 2018 by Carl Franks.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.


and that's a wrap on the whole thing, bestie πŸ₯ΉπŸ’– this page came from perl v5.28.1, dated 2019-01-12, and it's HTML::FormFu(3pm) β€” go build something iconic with it. periodt βœ¨πŸ¦‹

πŸ“¦ where this page comes from