The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

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.