HTML::FormFu(3pm)
β¨ 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 ofHTML::FormFu::Model::DBIC. As of"HTML::FormFu"v02.005, theHTML::FormFu::Model::DBICmodule 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: Becauseprocessis 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 callprocessagain yourself before usingsubmitted_and_valid, any of the methods listed underSUBMITTED FORM VALUES AND ERRORSorMODIFYING 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 exampleelements, which is an alias forelementβ the keys you give todefault_argsmust 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 withinsert_beforeorinsert_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::FilterHTML::FormFu::ConstraintHTML::FormFu::InflatorHTML::FormFu::ValidatorHTML::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>
π COPYRIGHT AND LICENSE π
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
- debian bookworm: libhtml-formfu-perl 2.07000-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu jammy: libhtml-formfu-perl 2.07000-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu noble: libhtml-formfu-perl 2.07000-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms