The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Valiant::HTML::Form - HTML Form

SYNOPSIS

Given a model like:

    package Local::Person;

    use Moo;
    use Valiant::Validations;

    has first_name => (is=>'ro');
    has last_name => (is=>'ro');

    validates ['first_name', 'last_name'] => (
      length => {
        maximum => 20,
        minimum => 3,
      }
    );

Wrap a formbuilder object around it and generate HTML form field controls:

    use Valiant::HTML::Form 'form_for';

    my $person = Local::Person->new(first_name=>'J', last_name=>'Napiorkowski');
    $person->validate;

    form_for($person, sub($fb) {
      return  $fb->label('first_name'),
              $fb->input('first_name'),
              $fb->errors_for('first_name', +{ class=>'invalid-feedback' }),
              $fb->label('last_name'),
              $fb->input('last_name'),
              $fb->errors_for('last_name'+{ class=>'invalid-feedback' });
    });

Generates something like:

    <form accept-charset="UTF-8" id="new_person" method="post">
      <label for="person_first_name">First Name</label>
      <input id="person_first_name" name="person.first_name" type="text" value="John"/>
      <div class='invalid-feedback'>First Name is too short (minimum is 3 characters).</div>
      <label for="person_last_name">Last Name</label>
      <input id="person_last_name" name="person.last_name" type="text" value="Napiorkowski"/>
    </form>

DESCRIPTION

Export helper methods to properly create instances of Valiant::HTML::FormBuilder that will also wrap the builder in proper form tags.

Its possible other methods will move here from Valiant::HTML::FormBuilder to make it easier for people to build form tags without needed to create a full on builder. Please make you requests and demonstrated use cases in a ticket.

REQUIRED MODEL API

This (and Valiant::HTML::FormBuilder) wrap an object model that is expected to do the following interface.

to_model

This is an optional method. If this is supported, we call to_model on the wrapped object before using it on the form methods. This allows you to delegate the required API to a secondard object, which can result in a cleaner API depending on your designs and use cases.

in_storage

This is an optional method. If your object has a backing storage solution (such as your object is an instance of a DBIC Result Source) you can provide this method to influence how your object form tags are created. If provided this method should return a boolean when if true means that the object is representing data which is stored in the backing storage solution. Please note that this does not mean that the object is synchronized with the backing storage since its possible that the object has been changed by the user.

human_attribute_name

Optional. If provided, uses the model to look up a displayable version of the attribute name, for example used in a label for an input control. If not present we use Valiant::HTML::FormTags\_humanize to create a displayable name from the attribute name.

errors

Optional. Should return an instances of Valiant::Errors. If present will be used to lookup model and attribute errors.

Please note this currently is tried to behavior expected from Valiant::Errors but in the future we might try to make this tied to a defined interface rather than this concrete class.

has_errors

Optional if you don't use builder methods that are for displaying errors; required otherwise. A boolean that indicates if your model has errors or not. Used to determined if error_classes are merged into class and in a few similar places.

i18n

Optional. If provided should return an instance of Valiant::I18N. Used in a few places to support translation tags.

model_name

Optional. If provide should return an instance of Valiant::Name. Used in a few places where we default a value to a human readable version of the model name. If you don't have this method we fall back to guessing something based on the string name of the model.

primary_columns

Optional. When a model does in_storage and its a nested model, when this method exists we use it to get a list of primary columns for the underlying storage and then add them as hidden fields. This is needed particularly with one - many style relationships so that we find the right record in the storage model to update.

NOTE: This method requirement is subject to change. It feels a bit too tightly bound to the idea of and ORM and to DBIx::Class in particular.

is_marked_for_deletion

Optional, but should be supported if your model supports a storage backend. A boolean that indicates if the model is currently marked for deletion upon successful validation. Used for things like radio and checkbox collections when the state should be 'unchecked' even if the model is still in storage.

EXPORTABLE FUNCTIONS

The following functions can be exported by this library

form_for

    form_for($person, sub($fb) {
      $fb->input('name');
      $fb->label('name');
    });

    # Generates something like:

    <form accept-charset="UTF-8" id="new_person" method="post">
      <label for="person_name">Name</label>
      <input id="person_name" name="person.name" type="text" value="John"/>
    </form>

Given a model as described above, wrap a Valiant::HTML::FormBuilder instance around it which provides methods for generating valid HTML form output. This provides a view logic centered method for creating sensible and reusable form controls which include server generated error output from validation.

See Valiant::HTML::FormBuilder for more on the formbuilder API.

\%options are used to influence the builder creation as well as pass attributes to the generated form tag. Options are as follows:

as

Supplies the name argument for Valiant::HTML::FormBuilder. This is generally used to set the top namespace for your field IDs and name attributes.

method

Sets the form attribute method. Generally defaults to post or patch (when in_storage is supported and the model is marked for updating of an existing model).

action

Should be the URL that the form with post to.

data

a hashref of HTML tag <data> attributes.

class
style

HTML attributes that get merged into the html options (below)

html

a hashref of items that will get rendered as HTML attributes for the form.

namespace

Optional. Can use used to prepend a namespace to your form IDs

index

Optional. When processing a collection model this will be the index of the current model.

builder

The form builder. Defaults to Valiant::HTML::FormBuilder. You can set this if you create your own formbuilder subclass and want to use that.

The last argument should be a reference to a subroute that will receive the created formbuilder object and should return a string, or array of strings that will be flattened and displayed as your form elements. Any strings returns not marked as safe via Valiant::HTML::SafeString will be encoded and turned safe so be sure to mark any raw strings correctly unless you want double encoding issues.

fields_for

    fields_for($sub_model_name, $model, $options, sub($fb) {
      $fb->input($field);
    });

Create an instance of a formbuilder that represents a sub model (that is a model with is associated with a parent model under an attribute of that parent.

Unless you are doing very customized form generation you'll probably use this as a method of a formbuilder such as Valiant::HTML::FormBuilder. However there was no reason for me to not expose the method publically for users who need it.

SEE ALSO

Valiant, Valiant::HTML::FormBuilder

AUTHOR

See Valiant

COPYRIGHT & LICENSE

See Valiant