Kelp with HTML::FillInForm

22 views
Skip to first unread message

mla

unread,
Feb 20, 2014, 6:41:52 PM2/20/14
to perl...@googlegroups.com
Has anyone used HTML::FillInForm with Kelp?

It looks like the most logical place to rewrite the response is in Kelp::Response::render().
render() handles encoding at the very end though, and I think that technically I'd need to decode the body, run it through HTML::FillInForm, and then re-encode it, correct?

So rather than that, my Kelp::Response subclass currently has:

sub render {
  my $self = shift;
  my $body = shift // '';

  # status code and content type logic taken from parent class
  # See Kelp::Response::render()

  # Set code 200 if the code has not been set
  $self->set_code(200) unless $self->code;

  # If no content_type is set, then set it based on
  # the type of $body - JSON or HTML.
  unless ($self->content_type) {
    ref($body) ? $self->json : $self->html;
  }

  # sticky forms
  if ($self->code == 200 && $self->content_type =~ m{text/html}i) {
    if ($body =~ /<\s*form/i) {
      $body = HTML::FillInForm->fill(\$body, $self->app->req);
    }
  }

  return $self->SUPER::render($body, @_);
}

Suggestions? 

Stefan Geneshky

unread,
Feb 21, 2014, 12:24:59 AM2/21/14
to perl...@googlegroups.com
I haven't used HTML::FillInForm in years (probably since the days of CGI). I would probably have my template engine handle the population and default values of the form. If you have set your mind on using HTML::FillInForm, perhaps a better way would be to create a render_form method and use it for those routes that contain forms. If you want a catch-all render that always handles forms, then your approach might be the right one.
At the end, of course, it's whatever works for you best. 

As for your sub-classed render, it seems to me that it is repeating some of the code that it already inherits. Perhaps a more compact version, which uses HTML::FillInForm would be:

sub render {
   my $self = shift;
   my $body = shift // '';

   # sticky forms
   if ($self->code == 200 && $self->content_type =~ m{text/html}i) {
       if ($body =~ /<\s*form/i) {
          $body = HTML::FillInForm->fill(\$body, $self->app->req);
       }
   }

   return $self->SUPER::render( $body, @_ );
}

Stefan

mla

unread,
Feb 21, 2014, 12:53:52 AM2/21/14
to perl...@googlegroups.com


On Thursday, February 20, 2014 9:24:59 PM UTC-8, Stefan Geneshky wrote:
I haven't used HTML::FillInForm in years (probably since the days of CGI). I would probably have my template engine handle the population and default values of the form. If you have set your mind on using HTML::FillInForm, perhaps a better way would be to create a render_form method and use it for those routes that contain forms. If you want a catch-all render that always handles forms, then your approach might be the right one.
At the end, of course, it's whatever works for you best. 

As for your sub-classed render, it seems to me that it is repeating some of the code that it already inherits. Perhaps a more compact version, which uses HTML::FillInForm would be:

sub render {
   my $self = shift;
   my $body = shift // '';

   # sticky forms
   if ($self->code == 200 && $self->content_type =~ m{text/html}i) {
       if ($body =~ /<\s*form/i) {
          $body = HTML::FillInForm->fill(\$body, $self->app->req);
       }
   }

   return $self->SUPER::render( $body, @_ );
}

Thanks, Stefan. Yes, I didn't like duplicating the code but with this version, we potentially miss content if the status code or content type haven't yet been set. 

Any example Kelp apps that can demonstrate good handling of form population and defaults? What are the most common idioms currently?

Thanks.

Stefan Geneshky

unread,
Feb 21, 2014, 12:30:39 PM2/21/14
to perl...@googlegroups.com
You're correct. The above code will miss the status code and content type if they haven't been set yet.
Here is an example of how I'd have the template engine populate the forms for me:

In lib/MyApp.pm:
sub home {
    my $self = shift;
    $self->template( 'home', $self->req->parameters->as_hashref );
}

In views/home.tt:
<form>
    <input name="email" value="[% email %]">
    <input name="first_name" value="[% first_name %]">
    <input name="last_name" value="[% last_name %]">
    <input name="phone" value="[% phone %]">
</form>
Note that I am using Template::Tiny, which is the default template engine that comes with Kelp, and it only covers a limited subset of Template::Toolkit's functionality.

Maurice Aubrey

unread,
Feb 21, 2014, 8:34:10 PM2/21/14
to perl-kelp


On Fri, Feb 21, 2014 at 9:30 AM, Stefan Geneshky <stefa...@gmail.com> wrote:
> You're correct. The above code will miss the status code and content type if
> they haven't been set yet.
> Here is an example of how I'd have the template engine populate the forms
> for me:
>
> In lib/MyApp.pm:
>
> sub home {
>     my $self = shift;
>     $self->template( 'home', $self->req->parameters->as_hashref );
> }
>
>
> In views/home.tt:
>
> <form>
>     <input name="email" value="[% email %]">
>     <input name="first_name" value="[% first_name %]">
>     <input name="last_name" value="[% last_name %]">
>     <input name="phone" value="[% phone %]">
> </form>
>
> Note that I am using Template::Tiny, which is the default template engine
> that comes with Kelp, and it only covers a limited subset of
> Template::Toolkit's functionality.

Thanks for the example. And you'd handle the HTML encoding within the controller or the view? Looking at the Template::Tiny source, I don't see any direct handling of encoding there.

So the pattern would be something like this? pseudo-code:

sub home {
  my $self = shift;

  my $data;
  if ($self->req->is_post) {
    $data = $self->req->parameters->as_hashref;
  } else { # form defaults
    $data = ... load data/object, whatever
  }

  $self->template('home', html_encode($vars));
}

Stefan Geneshky

unread,
Feb 22, 2014, 7:42:37 AM2/22/14
to perl...@googlegroups.com

Yes, your pseudo code is correct. If you used Template::Toolkit, I believe it does the encoding for you. There is a ready Kelp module for it. Look up Kelp::Module::Template::Toolkit.

Stefan

Reply all
Reply to author
Forward
0 new messages