NAME
Catalyst::View::Valiant::HTMLBuilder - Per Request, strongly typed Views in code
SYNOPSIS
package Example::View::HTML::Home;
use Moo;
use Catalyst::View::Valiant::HTMLBuilder
-tags => qw(div blockquote form_for fieldset),
-helpers => qw($sf),
-views => 'HTML::Layout', 'HTML::Navbar';
has info => (is=>'rw', predicate=>'has_info');
has person => (is=>'ro', required=>1);
sub render($self, $c) {
html_layout page_title => 'Sign In', sub($layout) {
html_navbar active_link=>'/',
blockquote +{ if=>$self->has_info,
class=>"alert alert-primary",
role=>"alert" }, $self->info,
div $self->person->$sf('Welcome {:first_name} {:last_name} to your Example Homepage');
div {if=>$self->person->profile_incomplete}, [
blockquote {class=>"alert alert-primary", role=>"alert"}, 'Please complete your profile',
form_for $self->person, sub($self, $fb, $person) {
fieldset [
$fb->legend,
div +{ class=>'form-group' },
$fb->model_errors(+{show_message_on_field_errors=>'Please fix validation errors'}),
div +{ class=>'form-group' }, [
$fb->label('username'),
$fb->input('username'),
$fb->errors_for('username'),
],
div +{ class=>'form-group' }, [
$fb->label('password'),
$fb->password('password'),
$fb->errors_for('password'),
],
div +{ class=>'form-group' }, [
$fb->label('password_confirmation'),
$fb->password('password_confirmation'),
$fb->errors_for('password_confirmation'),
],
],
fieldset $fb->submit('Complete Account Setup'),
],
],
};
}
1;
DESCRIPTION
WARNINGS: Experimental code that I might need to break back compatibility in order to fix issues.
This is a Catalyst::View subclass that provides a way to write views in code that are strongly typed and per request. It also integrates with several of Valiant's HTML form generation code modules to make it easier to create HTML forms that properly synchronize with your Valiant models for displaying errors and performing validation.
Unlike most Catalyst views, this view is 'per request' in that it is instantiated for each request. This allows you to store per request state in the view object as well as localize view specific logic to the view object. In particular it allows you to avoid or reduce using the stash in order to pass values from the controller to the view. I think this can make your views more robust and easier to support for the long term. It builds upons Catalyst::View::BasePerRequest which provides the per request behavior so you should take a look at the documentation and example controller integration in that module in order to get the idea.
As a quick example here's a possible controller that might invoke the view given in the SYNOPSIS:
package Example::Controller::Home;
use Moose;
use MooseX::MethodAttributes;
extends 'Catalyst::Controller';
sub index($self, $c) {
my $view = $c->view('HTML::Home', person=>$c->user);
if( # Some condition ) {
$view->info('You have been logged in');
}
}
1;
This will then work with the commonly used Catalyst::Action::RenderView or my Catalyst::ActionRole::RenderView to produce a view response and set it as the response body.
Additionally, this view allows you to import HTML tags from Valiant::HTML::Util::TagBuilder as well as HTML tag helper methods from Valiant::HTML::Util::FormTags and Valiant::HTML::Util::Form into your view code. You should take a look at the documentation for those modules to see what is available. Since Valiant::HTML::Util::TagBuilder includes basic flow control and logic this gives you a bare minimum templating system that is completely in code. You can import some utility methods as well as other views into your view (please see the "EXPORTS" section below for more details). This is currently lightly documented so I recommend also looking at the test cases as well as the example Catalyst application included in the distribution under the example/
directory.
ATTRIBUTES
This class inherits all of the attributes from Catalyst::View::BasePerRequest
METHODS
This class inherits all of the methods from Catalyst::View::BasePerRequest as well as:
form
Returns the current form
object.
tags
A convenience method to get the tags
object from the current form
.
safe
Marks a string as safe to render by first escaping it and then wrapping it in a Valiant::HTML::SafeString object.
raw
Marks a string as safe to render by wrapping it in a Valiant::HTML::SafeString object.
safe_concat
Given one or more strings and / or Valiant::HTML::SafeString objects, returns a new Valiant::HTML::SafeString object that is the concatenation of all of the strings.
escape_html
Given a string, returns a new string that is the escaped version of the original string.
read_attribute_for_html
Given an attribute name, returns the value of that attribute if it exists. If the attribute does not exist, it will die.
attribute_exists_for_html
Given an attribute name, returns true if the attribute exists and false if it does notu.
formbuilder_class
sub formbuilder_class { 'Example::FormBuilder' }
Provides an easy way to override the default formbuilder class. By default it will use Valiant::HTML::FormBuilder. You can override this method to return a different class via a subclass of this view.
EXPORTS
-tags
Export any HTML tag supported in Valiant::HTML::TagBuilder as well as tag helpers from Valiant::HTML::Util::FormTags and Valiant::HTML::Util::Form. Please note the tr
tag must be imported by the trow
name since tr
is a reserved word in Perl.
-helpers
Export the following functions as well as any named method from the current controller and application context:
- $user
-
The current logged in user if any (via
$c->user
) - $sf
-
$person->$sf('Hi there {:first_name} {:last_name} !!')
Exports a coderef helper that wraps the
sf
method in Valiant::HTML::TagBuilder. Useful when you have an object whos methods you want as values in your view. - content
- content_for
- content_append
- content_replace
- content_around
-
Wraps the named methods from Catalyst::View::BasePerRequest for export. You can still call them directly on the view object if you prefer.
- path
-
Given an instance of Catalyst::Action or the name of an action, returns the full path to that action as a url. Basically a wrapper over
uri_for
that will die if it can't find the action. It also properly support relatively named actions.
-views
Create export wrappers for the named Catalyst views. Export names will be snake cased versions of the given view names.
SUBCLASSING
You can subclass this view in order to provide your own default behavior and additional methods.
package View::Example::View;
use Moo;
use Catalyst::View::Valiant
-tags => qw(blockquote label_tag);
sub formbuilder_class { 'Example::FormBuilder' }
sub stuff2 {
my $self = shift;
$self->label_tag('test', sub {
my $view = shift;
die unless ref($view) eq ref($self);
});
return $self->tags->div('stuff2');
}
sub stuff3 :Renders {
blockquote 'stuff3',
shift->div('stuff333')
}
1;
Then the view View::Example::View
can be used in exactly the same way as this view.
TIPS & TRICKS
Creating render methods
Often you will want to break up your render method into smaller chunks. You can do this by creating methods that return Valiant::HTML::SafeString objects. You can then call these methods from your render method. Here's an example:
sub simple :Renders {
my $self = shift;
return div "Hey";
}
You can then call this method from another render method:
sub complex :Renders {
my $self = shift;
return $self->simple;
}
Or use it directly in your main render method:
sub render {
my $self = shift;
return $self->simple;
}
Please note you need to add the ':Renders' attribute to your method in order for it to be exported as a render method. You don't need to do that on the main render method in your class because we handle that for you.
Calling for view fragments
You can call for the response of any view's method wish is marked as a render method.
package Example::View::Fragments;
use Moo;
use Catalyst::View::Valiant
-tags => qw(div);
sub stuff4 :Renders { div 'stuff4' }
1;
Then in your main view:
package Example::View::Hello;
use Moo;
use Catalyst::View::Valiant
-views => qw(Fragments);
sub render {
my $self = shift;
return fragment->stuff4;
}
You can even call them in a controller:
sub index :Path {
my ($self, $c) = @_;
$c->res->body($c->view('Fragments')->stuff4);
}
SEE ALSO
Valiant, Valiant::HTML::Util::Form, Valiant::HTML::Util::FormTags, Valiant::HTML::Util::Tagbuilder, Valiant::HTML::SafeString.
AUTHOR
See Valiant
COPYRIGHT & LICENSE
See Valiant