Skip to content

Commit

Permalink
Fix required form radio/checkbox fields (#1643)
Browse files Browse the repository at this point in the history
* Fix required form radio/checkbox fields

* Shift scripts to it's own JS file. Update markup. Tweaks.

* add inline docblock

* Add test to check for loaded script

* Fix incorrect radio field values being passed to the emails

* Tweak error notice

* Fix test_render_field_radio unit test

* Update docs with info on coblocks_form_checkbox_required_text filter

* Fix test_required_checkbox_script test

* Remove jQuery dependency, rewrite everything with vanilla JS

* Update unit tests

* adjust docs wording

Co-authored-by: Rich Tabor <hi@richtabor.com>
Co-authored-by: AnthonyLedesma <anthonymledesma@gmail.com>
  • Loading branch information
3 people authored Sep 3, 2020
1 parent f4f1f45 commit 19426b2
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 8 deletions.
1 change: 1 addition & 0 deletions .dev/config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module.exports = {

'js/coblocks-accordion-polyfill': path.resolve( process.cwd(), 'src/js/coblocks-accordion-polyfill.js' ),
'js/coblocks-accordion-carousel': path.resolve( process.cwd(), 'src/js/coblocks-accordion-carousel.js' ),
'js/coblocks-checkbox-required': path.resolve( process.cwd(), 'src/js/coblocks-checkbox-required.js' ),
'js/coblocks-datepicker': path.resolve( process.cwd(), 'src/js/coblocks-datepicker.js' ),
'js/coblocks-events': path.resolve( process.cwd(), 'src/js/coblocks-events.js' ),
'js/coblocks-fromEntries': path.resolve( process.cwd(), 'src/js/coblocks-fromEntries.js' ),
Expand Down
45 changes: 44 additions & 1 deletion .dev/tests/phpunit/includes/test-coblocks-form.php
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,7 @@ public function test_render_field_radio_empty_options() {
*/
public function test_render_field_radio() {

$this->expectOutputRegex( '/<label class="coblocks-radio-label" for="radio-option-1">Option 1<\/label><input id="radio-option-2" type="radio" name="field-radio\[value\]" value="Option 2" class="radio">/' );
$this->expectOutputRegex( '/<label class="coblocks-radio-label" for="choose-one-option-1">Option 1<\/label><input id="choose-one-option-2" type="radio" name="field-choose-one\[value\]" value="Option 2" class="radio">/' );

echo $this->coblocks_form->render_field_radio(
[
Expand Down Expand Up @@ -508,6 +508,49 @@ public function test_render_field_checkbox_inline() {

}

/**
* Test the checkbox required class is added to the markup as expected
*/
public function test_render_field_checkbox_required_class() {

$this->expectOutputRegex( '/<div class="coblocks-field checkbox required">/' );

echo $this->coblocks_form->render_field_checkbox(
[
'options' => [
'option-1' => 'Option 1',
'option-2' => 'Option 2',
],
'required' => true,
],
''
);

}

/**
* Test that the required checkbox field script is loaded when checkboxes
* are set to required
*/
public function test_required_checkbox_script() {

$this->coblocks_form->render_field_checkbox(
[
'options' => [
'option-1' => 'Option 1',
'option-2' => 'Option 2',
],
'required' => true
],
''
);

global $wp_scripts;

$this->assertArrayHasKey( 'coblocks-checkbox-required', $wp_scripts->registered );

}

/**
* Test the website field markup is as expected
*/
Expand Down
2 changes: 2 additions & 0 deletions .dev/tests/phpunit/test-class-coblocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ public function test_final_build_assets_exist() {
'js' => [
'dist/coblocks.js',
'dist/js/coblocks-accordion-polyfill.js',
'dist/js/coblocks-checkbox-required.js',
'dist/js/coblocks-datepicker.js',
'dist/js/coblocks-fromEntries.js',
'dist/js/coblocks-google-maps.js',
Expand All @@ -195,6 +196,7 @@ public function test_final_build_assets_exist() {
'dist/js/vendors/flickity.js',
'dist/js/vendors/slick.js',
'src/js/coblocks-accordion-polyfill.js',
'src/js/coblocks-checkbox-required.js',
'src/js/coblocks-datepicker.js',
'src/js/coblocks-fromEntries.js',
'src/js/coblocks-google-maps.js',
Expand Down
19 changes: 19 additions & 0 deletions docs/hooks/forms-block.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,22 @@ function coblocks_form_sent_message() {
}
add_filter( 'coblocks_form_sent_notice', 'coblocks_form_sent_message' );
```

## Customize the Checkbox Required Text

The following `PHP` filter can be used to set a custom response when a required checkbox group has no options set before submitting the form.

```php
/**
* Set a custom error message to display when a required checkbox
* group has no options set before submitting the form.
*
* @return string Form submission success message
*/
function coblocks_checkbox_required_text() {

return __( 'Please check at least one checkbox.', 'textdomain' );

}
add_filter( 'coblocks_form_checkbox_required_text', 'coblocks_checkbox_required_text' );
```
43 changes: 36 additions & 7 deletions includes/class-coblocks-form.php
Original file line number Diff line number Diff line change
Expand Up @@ -487,9 +487,10 @@ public function render_field_radio( $atts ) {

$the_options = array_filter( $atts['options'] );

$label = isset( $atts['label'] ) ? $atts['label'] : __( 'Choose one', 'coblocks' );
$label_desc = sanitize_title( $label ) !== 'choose-one' ? sanitize_title( $label ) : 'radio';
$label_slug = $radio_count > 1 ? sanitize_title( $label_desc . '-' . $radio_count ) : sanitize_title( $label_desc );
$label = isset( $atts['label'] ) ? $atts['label'] : __( 'Choose one', 'coblocks' );
$label_desc = sanitize_title( $label ) !== 'choose-one' ? sanitize_title( $label ) : 'choose-one';
$label_slug = $radio_count > 1 ? sanitize_title( $label_desc . '-' . $radio_count ) : sanitize_title( $label_desc );
$required_attr = ( isset( $atts['required'] ) && $atts['required'] ) ? ' required' : '';

ob_start();

Expand All @@ -503,14 +504,15 @@ public function render_field_radio( $atts ) {

}

foreach ( $the_options as $value ) {
foreach ( $the_options as $key => $value ) {

printf(
'<input id="%1$s" type="radio" name="field-%2$s[value]" value="%3$s" class="radio">
<label class="coblocks-radio-label" for="%1$s">%4$s</label>',
'<input id="%1$s" type="radio" name="field-%2$s[value]" value="%3$s" class="radio"%4$s>
<label class="coblocks-radio-label" for="%1$s">%5$s</label>',
esc_attr( $label_slug . '-' . sanitize_title( $value ) ),
esc_attr( $label_slug ),
esc_attr( $value ),
$key === 0 ? esc_attr( $required_attr ) : '',
esc_html( $value )
);

Expand Down Expand Up @@ -600,10 +602,37 @@ public function render_field_checkbox( $atts ) {

$label = isset( $atts['label'] ) ? $atts['label'] : __( 'Select', 'coblocks' );
$label_slug = $checkbox_count > 1 ? sanitize_title( $label . '-' . $checkbox_count ) : sanitize_title( $label );
$required = ( isset( $atts['required'] ) && $atts['required'] );

if ( $required ) {

wp_enqueue_script(
'coblocks-checkbox-required',
CoBlocks()->asset_source( 'js' ) . 'coblocks-checkbox-required.js',
array(),
COBLOCKS_VERSION,
true
);

}

ob_start();

print( '<div class="coblocks-field">' );
printf(
'<div class="coblocks-field checkbox%1$s">
%2$s',
$required ? esc_attr( ' required' ) : '',
$required ? sprintf(
'<div class="required-error hidden">%s</div>',
/**
* Filter the checkbox required text that displays when no checkbox is
* selected when the form is submitted.
*
* @param string $error_text Error text displayed to the user.
*/
(string) apply_filters( 'coblocks_form_checkbox_required_text', esc_html__( 'Please select at least one checkbox.', 'coblocks' ) )
) : ''
);

$this->render_field_label( $atts, $label, $checkbox_count );

Expand Down
4 changes: 4 additions & 0 deletions src/blocks/form/styles/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
margin: 1.25rem 0 3px 0;
}

.required-error.hidden {
display: none;
}

.coblocks-field,
select {
margin: 0 0 1.25rem 0;
Expand Down
30 changes: 30 additions & 0 deletions src/js/coblocks-checkbox-required.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
document.addEventListener( 'DOMContentLoaded', function() {
document.querySelectorAll( '.coblocks-form form' ).forEach( form => {

let requiredErrorDiv = form.getElementsByClassName( 'required-error' )[0];

// No required checkboxes
if ( ! form.querySelectorAll( '.coblocks-field.checkbox.required' ).length ) {
return;
}

// Form Submit Event Listener
form.addEventListener( 'submit', event => {
let selectedCheckboxes = form.querySelectorAll( '.coblocks-field.checkbox.required input[type="checkbox"]:checked' ).length;
if ( selectedCheckboxes === 0 ) {
requiredErrorDiv.style.display = 'block';
event.preventDefault();
return;
}
requiredErrorDiv.style.display = 'none';
} );

// Required Checkbox Event Listener
form.querySelectorAll( '.coblocks-field.checkbox.required input[type="checkbox"]' ).forEach( requiredCheckbox => {
requiredCheckbox.addEventListener( 'change', () => {
requiredErrorDiv.style.display = 'none';
} );
} );

} );
} );

0 comments on commit 19426b2

Please sign in to comment.