Skip to content

Instantly share code, notes, and snippets.

@dim0xff
Last active December 26, 2015 21:59
Show Gist options
  • Save dim0xff/7219557 to your computer and use it in GitHub Desktop.
Save dim0xff/7219557 to your computer and use it in GitHub Desktop.
just a try to speedup Repeatable fields Put into HTML/FormHandlerX/Field/TraitFor/Repeatable/Speedup.pm
package HTML::FormHandlerX::Field::TraitFor::Repeatable::Speedup;
=head1 NAME
HTML::FormHandlerX::Field::TraitFor::Repeatable::Speedup - just a try to speedup
Repeatable fields
=head1 DESCRIPTION
Every time you validate your form, which has Repeatable fields, for each value in input for
repeatable field will be created field with needed type. So when you have 10 input values, you
probably will not recognize that it is working slowly.
This trait tries to optimize that mechanism: it creates permanent reusable fields on demand.
=head1 WARNING
Probably it will break ability to change attributes for embedded fields (required, disabled etc.).
=head1 SYNOPSYS
# Your cart form
package My::Cart;
use HTML::FormHandler::Moose;
extends 'HTML::FormHandler';
has_field 'products' => (
type => 'Repeatable',
traits => ['HTML::FormHandlerX::Field::TraitFor::Repeatable::Speedup'],
);
has_field 'products.id' => (type => 'PosInteger', required => 1, );
has_field 'products.quantity' => (type => 'PosInteger', required => 1, );
has_field 'products.options' => (
type => 'Repeatable',
traits => ['HTML::FormHandlerX::Field::TraitFor::Repeatable::Speedup'],
);
has_field 'products.options.option_id' => (type => 'PosInteger', required => 1, );
has_field 'products.options.value_id' => (type => 'PosInteger', required => 1, );
1;
=cut
use HTML::FormHandler::Moose::Role;
use utf8;
use strict;
use warnings;
has _cloned_elements => (
is => 'rw',
isa => 'ArrayRef',
default => sub { [] },
);
sub init_state {
my $self = shift;
# must clear out instances built last time
unless ( $self->has_contains ) {
if ( $self->num_fields == 1 && $self->field('contains') ) {
$self->field('contains')->is_contains(1);
$self->contains( $self->field('contains') );
}
else {
$self->contains( $self->create_element );
}
}
}
around clone_element => sub {
my ( $orig, $self, $index ) = @_;
return $self->_cloned_elements->[$index]
if exists $self->_cloned_elements->[$index];
my $field = $self->$orig($index);
$self->_cloned_elements->[$index] = $field;
return $field;
};
after clone_fields => sub {
my ( $self, $parent, $fields ) = @_;
for my $field ( @{$fields} ) {
$field->can('_cloned_elements') && $field->_cloned_elements( [] );
}
};
use namespace::autoclean;
1;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment