NAME
Mojolicious::Plugin::FormFields - Use objects and data structures in your forms
SYNOPSIS
$self->plugin('FormFields')
# In your controller
sub edit
{
my $self = shift;
my $user = $self->users->find($self->param('id'));
$self->stash(user => $user);
}
sub update
{
my $self = shift;
$self->users->update($self->param('user'));
}
# In your view
field('user.name')->text
field('user.age')->select([10,20,30])
field('user.password')->password
field('user.taste')->radio('me_gusta')
field('user.taste')->radio('estoy_harto_de')
field('user.orders.0.id')->hidden
# Fields for a collection
my $kinfolk = field('user.kinfolk');
for my $person (@$kinfolk) {
$person->hidden('id')
$person->text('name')
}
# Or, scope it to the 'user' param
my $user = fields('user');
$user->hidden('id')
$user->text('name')
$user->label('admin')
$user->checkbox('admin')
$user->password('password')
$user->select('age', [ [ X => 10], [Dub => 20] ])
$user->file('avatar')
$user->textarea('bio', size => '10x50')
my $kinfolk = $user->fields('kinfolk');
for my $person (@$kinfolk) {
$person->text('name')
# ...
}
DESCRIPTION
Mojolicious::Plugin::FormFields binds objects and data structures to form fields.
CREATING FIELDS
Fields can be bound to a hash, an array, something blessed, or any combination of the three. They are created by calling the "field"
helper with a path to the value you want to bind, and then calling the desired HTML input method
field('user.name')->text
Is the same as
text_field 'user.name', $user->name, id => 'user-name'
(though Mojolicious::Plugin::FormFields
sets type="text"
).
Field names/paths are given in the form target.accessor1 [ .accessor2 [ .accessorN ] ]
where target
is an object or data structure and accessor
is a method, hash key, or array index. The target must be in the stash under the key target
or provided as an argument to "field"
.
Some examples:
field('users.0.name')->text
Is the same as
text_field 'users.0.name', $users->[0]->name, id => 'users-0-name'
And
field('item.orders.0.XAJ123.quantity')->text
Is equivalent to
text_field 'item.orders.0.XAJ123.quantity', $item->orders->[0]->{XAJ123}->quantity, id => 'item-orders-0-XAJ123-quantity'
As you can see DOM IDs are always created.
Here the target key book
does not exist in the stash so the target is supplied
field('book.upc', $item)->text
If a value for the flattened representation exists (e.g., from a form submission) it will be used instead of the value pointed at by the field name (desired behavior?). This is the same as Mojolicious' Tag Helpers.
Options can also be provided
field('user.name')->text(class => 'input-text', 'data-name' => 'xxx')
See "SUPPORTED FIELDS" for the list of HTML input creation methods.
STRUCTURED REQUEST PARAMETERS
Structured request parameters for the bound object/data structure are available via Mojolicious::Controller
's param method. Nested parameters can not be accessed via Mojo::Message::Request
.
A request with the parameters user.name=nameA&user.email=email&id=123
can be accessed in your action like
my $user = $self->param('user');
$user->{name};
$user->{email};
Other parameters can be accessed as usual
$id = $self->param('id');
The flattened parameter can also be used
$name = $self->param('user.name');
See Mojolicious::Plugin::ParamExpand for more info.
SCOPING
Fields can be scoped to a particular object/structure via the "fields"
helper
my $user = fields('user');
$user->text('name');
$user->hidden('id');
When using fields
you must supply the field's name to the HTML input method, otherwise the calls are the same as they are with field
.
COLLECTIONS
You can also create fields scoped to elements in the collection
my $addresses = field('user.addresses');
for my $addr (@$addresses) {
# field('user.addresses.N.id')->hidden
$addr->hidden('id');
# field('user.addresses.N.street')->text
$addr->text('street');
# field('user.addresses.N.city')->select([qw|OAK PHL LAX|])
$addr->select('city', [qw|OAK PHL LAX|]);
}
Or, for fields that are already scoped
my $user = fields('user')
$user->hidden('id');
my $addressess = $user->fields('addresses');
for my $addr (@$addresses) {
$addr->hidden('id')
# ...
}
You can also access the underlying object and it's position within a collection via the object
and index
methods.
<% for my $addr (@$addresses) { %>
<div id="<%= dom_id($addr->object) %>">
<h3>Address #<%= $addr->index + 1 %></h3>
<%= $addr->hidden('id') %>
...
</div>
<% } %>
METHODS
field
field($name)->text
field($name, $object)->text
Arguments
$name
The field's name, which can also be the path to its value in the stash. See "CREATING FIELDS".
$object
Optional. The object used to retrieve the value specified by $name
. Must be a reference to a hash, an array, or something blessed. If not given the value will be retrieved from the stash or, for previously submitted forms, the request parameter $name
.
Returns
An object than can be used to create HTML form fields, see "SUPPORTED FIELDS".
Errors
An error will be raised if:
$name
is not provided$name
cannot be retrieved from$object
$object
cannot be found in the stash and no default was given
Collections
See "COLLECTIONS"
fields
$f = fields($name)
$f->text('address')
$f = fields($name, $object)
$f->text('address')
Create form fields scoped to a parameter.
For example
% $f = fields('user')
%= $f->select('age', [10,20,30])
%= $f->textarea('bio')
Is the same as
%= field('user.age')->select([10,20,30])
%= field('user.bio')->textarea
Arguments
Same as "field".
Returns
An object than can be used to create HTML form fields scoped to the $name
argument, see "SUPPORTED FIELDS".
Errors
Same as "field".
Collections
See "COLLECTIONS"
SUPPORTED FIELDS
checkbox
field('user.admin')->checkbox(%options)
field('user.admin')->checkbox('yes', %options)
Creates
<input type="checkbox" name="user.admin" id="user-admin-1" value="1"/>
<input type="checkbox" name="user.admin" id="user-admin-yes" value="yes"/>
file
field('user.avatar')->file(%options);
Creates
<input id="user-avatar" name="user.avatar" type="file" />
hidden
field('user.id')->hidden(%options)
Creates
<input id="user-id" name="user.id" type="hidden" value="123123" />
input
field('user.phone')->input($type, %options)
For example
field('user.phone')->input('tel', pattern => '\d{3}-\d{4}')
Creates
<input id="user-phone" name="user.phone" type="tel" pattern="\d{3}-\d{4}" />
label
field('user.name')->label
field('user.name')->label('Nombre', for => "tu_nombre_hyna")
Creates
<label for="user-name">Name</label>
<label for="tu_nombre_hyna">Nombre</label>
password
field('user.password')->password(%options)
Creates
<input id="user-password" name="user.password" type="password" />
select
field('user.age')->select([10,20,30], %options)
field('user.age')->select([[Ten => 10], [Dub => 20], [Trenta => 30]], %options)
Creates
<select id="user-age" name="user.age">
<option value="10">10</option>
<option value="20">20</option>
<option value="30">30</option>
</select>
<select id="user-age" name="user.age">
<option value="10">Ten</option>
<option value="20">Dub</option>
<option value="30">Trenta</option>
</select>
radio
field('user.age')->radio('older_than_21', %options)
Creates
<input id="user-age-older_than_21" name="user.age" type="radio" value="older_than_21" />
text
field('user.name')->text(%options)
field('user.name')->text(size => 10, maxlength => 32)
Creates
<input id="user-name" name="user.name" value="sshaw" />
<input id="user-name" name="user.name" value="sshaw" size="10" maxlength="32" />
textarea
field('user.bio')->textarea(%options)
field('user.bio')->textarea(size => '10x50')
Creates
<textarea id="user-bio" name="user.bio">Proprietary and confidential</textarea>
<textarea cols="50" id="user-bio" name="user.bio" rows="10">Proprietary and confidential</textarea>
AUTHOR
Skye Shaw (sshaw AT lucas.cis.temple.edu)
SEE ALSO
Mojolicious::Plugin::TagHelpers, Mojolicious::Plugin::ParamExpand, MojoX::Validator
COPYRIGHT
Copyright (c) 2012 Skye Shaw.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.