Permalink
Browse files

support options groups for select fields

  • Loading branch information...
1 parent 580f727 commit 67dd0f5dcb22226dd65261e1a08c70a81b3f5919 @gshank committed May 11, 2012
@@ -227,6 +227,34 @@ This does a string compare.
Customize 'select_invalid_value' and 'select_not_multiple'. Though neither of these
messages should really be seen by users in a properly constructed select.
+=head1 Rendering
+
+The 'select' field can be rendered by the 'Select', 'RadioGroup', and 'CheckboxGroup'
+widgets. 'RadioGroup' is for a single select, and 'CheckboxGroup' is for a multiple
+select.
+
+Option groups can be rendered by providing an options arrays with 'group' elements
+containing options:
+
+ sub options_testop { (
+ {
+ group => 'First Group',
+ options => [
+ { value => 1, label => 'One' },
+ { value => 2, label => 'Two' },
+ { value => 3, label => 'Three' },
+ ],
+ },
+ {
+ group => 'Second Group',
+ options => [
+ { value => 4, label => 'Four' },
+ { value => 5, label => 'Five' },
+ { value => 6, label => 'Six' },
+ ],
+ },
+ ) }
+
=head1 Database relations
Also see L<HTML::FormHandler::TraitFor::Model::DBIC>.
@@ -406,7 +434,17 @@ sub _inner_validate_field {
}
# create a lookup hash
- my %options = map { $_->{value} => 1 } @{ $self->options };
+ my %options;
+ foreach my $opt ( @{ $self->options } ) {
+ if ( exists $opt->{group} ) {
+ foreach my $group_opt ( @{ $opt->{options} } ) {
+ $options{$group_opt->{value}} = 1;
+ }
+ }
+ else {
+ $options{$opt->{value}} = 1;
+ }
+ }
if( $self->has_many ) {
$value = [map { $_->{$self->has_many} } @$value];
}
@@ -63,7 +63,7 @@ has 'fields' => (
# both updates on the process call and updates from class applied roles
has 'update_subfields' => ( is => 'rw', isa => 'HashRef', builder => 'build_update_subfields',
traits => ['Hash'], handles => { clear_update_subfields => 'clear',
- has_update_subfields => 'count' }, init_arg => undef );
+ has_update_subfields => 'count' } );
sub build_update_subfields {{}}
# compatibility wrappers for result errors
@@ -621,6 +621,10 @@ If you do want a label with these fields, you must set the 'do_label' flag to 1:
has_field 'foo' ( type => 'Button', do_label => 1 );
+Select fields are also fairly complicated. They can be rendered with the
+'Select', 'RadioGroup', and 'CheckboxGroup' widgets. Option groups are also
+supported. See L<HTML::FormHandler::Field::Select>;
+
=head2 Rendering labels
A 'standard' label is built in the field if you don't supply one. The label
@@ -19,59 +19,84 @@ be set by supplying a default value or from params input.
=cut
-sub render_element {
+sub render {
my ( $self, $result ) = @_;
$result ||= $self->result;
+ my $output = $self->render_element( $result );
+ return $self->wrap_field( $result, $output );
+}
- my $id = $self->id;
- my $fif = $result->fif;
- my %fif_lookup;
- @fif_lookup{@$fif} = () if $self->multiple;
+sub render_element {
+ my ( $self, $result ) = @_;
+ $result ||= $self->result;
- # create option label attributes
- my @option_label_class = ('checkbox');
- push @option_label_class, 'inline' if $self->get_tag('inline');
- my $opt_lattrs = process_attrs( { class => \@option_label_class } );
# loop through options
- my $index = 0;
my $output = '';
foreach my $option ( @{ $self->{options} } ) {
- $output .= qq{\n<label$opt_lattrs for="$id.$index">};
- my $value = $option->{value};
- $output .= qq{\n<input type="checkbox"};
- $output .= qq{ value="} . $self->html_filter($value) . '"';
- $output .= qq{ name="} . $self->html_name . '"';
- $output .= qq{ id="$id.$index"};
-
- # handle option attributes
- my $attrs = $option->{attributes} || {};
- if( defined $option->{disabled} && $option->{disabled} ) {
- $attrs->{disabled} = 'disabled';
+ if ( my $label = $option->{group} ) {
+ $label = $self->_localize( $label ) if $self->localize_labels;
+ my $attr = $option->{attributes} || {};
+ my $attr_str = process_attrs($attr);
+ my $lattr = $option->{label_attributes} || {};
+ my $lattr_str= process_attrs($attr);
+ $output .= qq{\n<div$attr_str><label$lattr_str>$label</label>};
+ foreach my $group_opt ( @{ $option->{options} } ) {
+ $output .= $self->render_option( $group_opt, $result );
+ }
+ $output .= qq{\n</div>};
}
- if ( defined $fif &&
- ( ( $self->multiple && exists $fif_lookup{$value} ) ||
- ( $fif eq $value ) ) ) {
- $attrs->{checked} = 'checked';
+ else {
+ $output .= $self->render_option( $option, $result );
}
- $output .= process_attrs($attrs);
- $output .= " />\n";
-
- # handle label
- my $label = $option->{label};
- $label = $self->_localize($label) if $self->localize_labels;
- $output .= $self->html_filter($label) || '';
- $output .= "\n</label>";
- $index++;
}
+ $self->reset_options_index;
return $output;
}
-sub render {
- my ( $self, $result ) = @_;
+sub render_option {
+ my ( $self, $option, $result ) = @_;
$result ||= $self->result;
- my $output = $self->render_element( $result );
- return $self->wrap_field( $result, $output );
+
+ # get existing values
+ my $fif = $result->fif;
+ my %fif_lookup;
+ @fif_lookup{@$fif} = () if $self->multiple;
+
+ # create option label attributes
+ my $lattr = $option->{label_attributes} || {};
+ push @{ $lattr->{class} }, 'checkbox';
+ push @{ $lattr->{class} }, 'inline' if $self->get_tag('inline');
+ my $lattr_str = process_attrs( $lattr );
+
+ my $id = $self->id . '.' . $self->options_index;
+ my $output .= qq{\n<label$lattr_str for="$id">};
+ my $value = $option->{value};
+ $output .= qq{\n<input type="checkbox"};
+ $output .= qq{ value="} . $self->html_filter($value) . '"';
+ $output .= qq{ name="} . $self->html_name . '"';
+ $output .= qq{ id="$id"};
+
+ # handle option attributes
+ my $attr = $option->{attributes} || {};
+ if( defined $option->{disabled} && $option->{disabled} ) {
+ $attr->{disabled} = 'disabled';
+ }
+ if ( defined $fif &&
+ ( ( $self->multiple && exists $fif_lookup{$value} ) ||
+ ( $fif eq $value ) ) ) {
+ $attr->{checked} = 'checked';
+ }
+ $output .= process_attrs($attr);
+ $output .= " />\n";
+
+ # handle label
+ my $label = $option->{label};
+ $label = $self->_localize($label) if $self->localize_labels;
+ $output .= $self->html_filter($label) || '';
+ $output .= "\n</label>";
+ $self->inc_options_index;
+ return $output;
}
1;
@@ -26,8 +26,22 @@ sub render_element {
my $output = '';
$output .= "<br />" if $self->get_tag('radio_br_after');
- foreach my $option ( @{ $self->options } ) {
- $output .= $self->render_option( $option, $result );
+ foreach my $option ( @{ $self->{options} } ) {
+ if ( my $label = $option->{group} ) {
+ $label = $self->_localize( $label ) if $self->localize_labels;
+ my $attr = $option->{attributes} || {};
+ my $attr_str = process_attrs($attr);
+ my $lattr = $option->{label_attributes} || {};
+ my $lattr_str= process_attrs($attr);
+ $output .= qq{\n<div$attr_str><label$lattr_str>$label</label>};
+ foreach my $group_opt ( @{ $option->{options} } ) {
+ $output .= $self->render_option( $group_opt, $result );
+ }
+ $output .= qq{\n</div>};
+ }
+ else {
+ $output .= $self->render_option( $option, $result );
+ }
$output .= '<br />' if $self->get_tag('radio_br_after');
}
$self->reset_options_index;
@@ -16,65 +16,99 @@ use Moose::Role;
use namespace::autoclean;
use HTML::FormHandler::Render::Util ('process_attrs');
+sub render {
+ my ( $self, $result ) = @_;
+ $result ||= $self->result;
+ my $output = $self->render_element( $result );
+ return $self->wrap_field( $result, $output );
+}
+
sub render_element {
my ( $self, $result ) = @_;
$result ||= $self->result;
- my $id = $self->id;
# create select element
- my $output = '<select name="' . $self->html_name . qq{" id="$id"};
- $output .= ' multiple="multiple"' if $self->multiple;
- $output .= ' size="' . $self->size . '"' if defined $self->size;
- $output .= process_attrs($self->element_attributes($result));
- $output .= '>';
+ my $output = $self->render_select_start( $result );
# create empty select
- my $index = 0;
if( defined $self->empty_select ) {
- my $label = $self->_localize($self->empty_select);
- $output .= qq{\n<option value="" id="$id.$index">$label</option>};
- $index++;
+ $output .= $self->render_empty_select;
}
- # current values
- my $fif = $result->fif;
- my %fif_lookup;
- @fif_lookup{@$fif} = () if $self->multiple;
-
# loop through options
foreach my $option ( @{ $self->{options} } ) {
- my $value = $option->{value};
- $output .= qq{\n<option value="} . $self->html_filter($value) . '"';
- $output .= qq{ id="$id.$index"};
-
- # handle option attributes
- my $attrs = $option->{attributes} || {};
- if( defined $option->{disabled} && $option->{disabled} ) {
- $attrs->{disabled} = 'disabled';
+ if ( my $label = $option->{group} ) {
+ $label = $self->_localize( $label ) if $self->localize_labels;
+ $output .= qq{\n<optgroup label="$label">};
+ foreach my $group_opt ( @{ $option->{options} } ) {
+ $output .= $self->render_option( $group_opt, $result );
+ }
+ $output .= qq{\n</optgroup>};
}
- if ( defined $fif &&
- ( ( $self->multiple && exists $fif_lookup{$value} ) ||
- ( $fif eq $value ) ) ) {
- $attrs->{selected} = 'selected';
+ else {
+ $output .= $self->render_option( $option, $result );
}
- $output .= process_attrs($attrs);
-
- # handle label
- my $label = $option->{label};
- $label = $self->_localize($label) if $self->localize_labels;
- $output .= '>' . ( $self->html_filter($label) || '' ) . '</option>';
- $index++;
}
+ $self->reset_options_index;
+
$output .= '</select>';
return $output;
}
-sub render {
+sub render_select_start {
my ( $self, $result ) = @_;
- $result ||= $self->result;
- my $output = $self->render_element( $result );
- return $self->wrap_field( $result, $output );
+
+ my $id = $self->id;
+ my $output = '<select name="' . $self->html_name . qq{" id="$id"};
+ $output .= ' multiple="multiple"' if $self->multiple;
+ $output .= ' size="' . $self->size . '"' if defined $self->size;
+ $output .= process_attrs($self->element_attributes($result));
+ $output .= '>';
+ return $output;
+}
+
+sub render_empty_select {
+ my $self = shift;
+
+ my $label = $self->_localize($self->empty_select);
+ my $id = $self->id . "." . $self->options_index;
+ my $output .= qq{\n<option value="" id="$id">$label</option>};
+ $self->inc_options_index;
+ return $output;
}
+sub render_option {
+ my ( $self, $option, $result ) = @_;
+ $result ||= $self->result;
+
+ # current values
+ my $fif = $result->fif;
+ my %fif_lookup;
+ @fif_lookup{@$fif} = () if $self->multiple;
+
+ my $value = $option->{value};
+ my $id = $self->id . '.' . $self->options_index;
+ my $output .= qq{\n<option value="} . $self->html_filter($value) . '"';
+ $output .= qq{ id="$id"};
+
+ # handle option attributes
+ my $attrs = $option->{attributes} || {};
+ if( defined $option->{disabled} && $option->{disabled} ) {
+ $attrs->{disabled} = 'disabled';
+ }
+ if ( defined $fif &&
+ ( ( $self->multiple && exists $fif_lookup{$value} ) ||
+ ( $fif eq $value ) ) ) {
+ $attrs->{selected} = 'selected';
+ }
+ $output .= process_attrs($attrs);
+
+ # handle label
+ my $label = $option->{label};
+ $label = $self->_localize($label) if $self->localize_labels;
+ $output .= '>' . ( $self->html_filter($label) || '' ) . '</option>';
+ $self->inc_options_index;
+ return $output;
+}
1;
Oops, something went wrong.

0 comments on commit 67dd0f5

Please sign in to comment.