Skip to content

Commit cb73116

Browse files
committed
Extending RadioButtonGroup to add the following functionality:
- Hide/show other elements based on the current selection - Disable certain buttons - Define custom JavaScript callbacks to be fired on value change.
1 parent 8cb18f7 commit cb73116

9 files changed

+102
-35
lines changed

docs/RadioButtonGroup.md

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,71 @@
22

33
The `RadioButtonGroup` widget renders a list of radio toggle buttons in the form of bootstrap button group. See the [documentation](http://getbootstrap.com/components/#btn-groups) for more styling information.
44

5-
**Basic usage with default settings:**
5+
####Basic usage with default settings:
66
~~~
77
use webtoolsnz\widgets\RadioButtonGroup;
88
9-
$form->field($model, 'status_id')->widget(RadioButtonGroup::className(), [
10-
'items' => [1 => 'Yes', 0 => 'No', 3 => 'Maybe']
9+
$form->field($model, 'status_id')->widget(RadioButtonGroup::class, [
10+
'items' => [1 => 'Yes', 0 => 'No', 3 => 'Maybe']
1111
]);
1212
~~~
1313
![screenshot](/docs/images/radio-button-group1.png?raw=true)
1414

1515

16-
**Customised active state (blue) and increased size:**
16+
####Customised active state (blue) and increased size:
1717
~~~
1818
use webtoolsnz\widgets\RadioButtonGroup;
1919
20-
$form->field($model, 'status_id')->widget(RadioButtonGroup::className(), [
21-
'items' => [1 => 'Yes', 0 => 'No', 3 => 'Maybe'],
22-
'options' => ['class' => 'btn-group-lg']
20+
$form->field($model, 'status_id')->widget(RadioButtonGroup::class, [
21+
'items' => [1 => 'Yes', 0 => 'No', 3 => 'Maybe'],
22+
'options' => ['class' => 'btn-group-lg']
2323
'itemOptions' => [
24-
'activeState' => 'btn active btn-primary'
24+
'activeState' => 'btn active btn-primary'
2525
]
2626
]) ?>
2727
~~~
2828
![screenshot](/docs/images/radio-button-group2.png?raw=true)
2929

30-
**Customised label states based on value:**
30+
####Customised label states based on value:
3131
Green for yes, red for no, orange for maybe.
3232
~~~
3333
use webtoolsnz\widgets\RadioButtonGroup;
3434
35-
$form->field($model, 'status_id')->widget(RadioButtonGroup::className(), [
36-
'items' => [1 => 'Yes', 0 => 'No', 3 => 'Maybe'],
37-
'itemOptions' => [
38-
'buttons' => [
39-
0 => ['activeState' => 'btn active btn-danger'],
35+
$form->field($model, 'status_id')->widget(RadioButtonGroup::class, [
36+
'items' => [1 => 'Yes', 0 => 'No', 3 => 'Maybe'],
37+
'itemOptions' => [
38+
'buttons' => [
39+
0 => ['activeState' => 'btn active btn-danger'],
4040
3 => ['activeState' => 'btn active btn-warning'],
4141
]
42-
]
42+
]
4343
]);
4444
~~~
45-
![screenshot](/docs/images/radio-button-group3.png?raw=true)
45+
![screenshot](/docs/images/radio-button-group3.png?raw=true)
46+
47+
48+
####Advanced itemOptions Example
49+
This advanced example shows how to:
50+
- Control the visibility of other elements on the page using the `showElements` and `hideElements` options.
51+
- Disable specific buttons using the `disabled` option.
52+
- Define a custom JavaScript function to be executed when the a button is selected.
53+
~~~php
54+
<?= $form->field($model, 'status_id')->widget(RadioButtonGroup::class, [
55+
'items' => [1 => 'Yes', 0 => 'No', 3 => 'Maybe'],
56+
'itemOptions' => [
57+
'buttons' => [
58+
0 => ['hideElements' => '.status-yes-info'],
59+
1 => [
60+
'showElements' => '.status-yes-info',
61+
'onSelect' => new JsExpression('function (e) {console.log("Yes was clicked!");}'),
62+
],
63+
3 => ['disabled' => 'true'],
64+
]
65+
]
66+
]); ?>
67+
68+
<div class="status-yes-info hidden">
69+
<p>I see you've chosen yes, are you sure thats right choice?</p>
70+
</div>
71+
72+
~~~

src/RadioButtonGroup.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66

77
namespace webtoolsnz\widgets;
88

9+
use yii\helpers\ArrayHelper;
910
use yii\helpers\Html;
1011
use yii\helpers\Json;
1112
use yii\widgets\InputWidget;
12-
use Yii;
1313

1414
/**
1515
* RadioButton renders a bootstrap style button group for radio options
@@ -100,10 +100,13 @@ public function run()
100100
$buttons = '';
101101

102102
foreach ($this->items as $value => $label) {
103+
$buttonOptions = ArrayHelper::getValue($this->itemOptions, ['buttons', $value], []);
103104
$buttons .= Html::button($label, [
104105
'data-value' => $value,
105106
'class' => $this->getButtonClass($value),
106-
'disabled' => $this->disabled,
107+
'disabled' => ArrayHelper::getValue($buttonOptions, 'disabled', $this->disabled),
108+
'data-show' => ArrayHelper::getValue($buttonOptions, 'showElements'),
109+
'data-hide' => ArrayHelper::getValue($buttonOptions, 'hideElements'),
107110
]);
108111
}
109112

src/assets/js/radio-button-group.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,29 @@
1313

1414
input.on('change', options.change).trigger('change');
1515

16-
el.find('button').on('click', function () {
17-
var value = $(this).data('value'),
16+
el.find('button').on('click', function (e) {
17+
var button = $(this),
18+
value = button.data('value'),
19+
oldValue = input.val(),
1820
buttonOptions = options.buttons[value],
1921
activeState = buttonOptions && buttonOptions['activeState'] ? buttonOptions['activeState'] : options['activeState'],
20-
defaultState = buttonOptions && buttonOptions['defaultState'] ? buttonOptions['defaultState'] : options['defaultState'];
22+
defaultState = buttonOptions && buttonOptions['defaultState'] ? buttonOptions['defaultState'] : options['defaultState'],
23+
showElements = $(button.data('show')),
24+
hideElements = $(button.data('hide'));
25+
26+
if (value == oldValue) {
27+
return;
28+
}
29+
30+
showElements.slideDown();
31+
hideElements.slideUp();
32+
33+
if (buttonOptions && typeof(buttonOptions.onSelect) === 'function') {
34+
buttonOptions.onSelect(e);
35+
}
2136

2237
input.val(value).trigger('change');
23-
$(this).attr('class', activeState).siblings().each(function () {
38+
button.attr('class', activeState).siblings().each(function () {
2439
var buttonOptions = options.buttons[$(this).data('value')],
2540
defaultState = buttonOptions && buttonOptions['defaultState'] ? buttonOptions['defaultState'] : options['defaultState'];
2641
$(this).attr('class', defaultState);

tests/RadioButtonGroupTest.php

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
<?php
22
namespace tests;
33

4+
use Spatie\Snapshots\Drivers\XmlDriver;
45
use Yii;
56
use tests\models\Payment;
67
use yii\helpers\VarDumper;
78
use yii\web\AssetBundle;
89
use webtoolsnz\widgets\RadioButtonGroup;
910
use webtoolsnz\widgets\RadioButtonGroupAsset;
11+
use Spatie\Snapshots\MatchesSnapshots;
12+
use yii\web\JsExpression;
13+
1014

1115
class RadioButtonGroupTest extends TestCase
1216
{
17+
use MatchesSnapshots;
18+
1319
public function testRenderWithNameAndId()
1420
{
1521
$out = RadioButtonGroup::widget([
@@ -18,8 +24,7 @@ public function testRenderWithNameAndId()
1824
'items' => [1 => 'Yes', 0 => 'No'],
1925
]);
2026

21-
$expected = '<div class="radio-button-group"><div id="radio_button_test" class="btn-group" data-field="#test"><button type="button" class="btn btn-default" data-value="1">Yes</button><button type="button" class="active btn btn-success" data-value="0">No</button></div></div><input type="hidden" id="test" name="test-widget-name">';
22-
$this->assertEquals($expected, $out);
27+
$this->assertMatchesSnapshot($out);
2328
}
2429

2530
public function testRenderWithOptions()
@@ -31,15 +36,27 @@ public function testRenderWithOptions()
3136
'options' => ['class' => 'foobar'],
3237
'itemOptions' => [
3338
'defaultState' => 'btn btn-primary',
34-
'activeState' => 'btn btn-primary active'
39+
'activeState' => 'btn btn-primary active',
40+
'buttons' => [
41+
1 => [
42+
'showElements' => '.show-if-yes',
43+
'hideElements' => '.show-if-no',
44+
'onSelect' => new JsExpression('function (e) {console.log(e);}')
45+
],
46+
0 => [
47+
'showElements' => '.show-if-no',
48+
'hideElements' => '.show-if-yes'
49+
],
50+
3 => ['disabled' => true],
51+
52+
]
3553
],
3654
'inputOptions' => [
3755
'class' => 'test-class',
3856
]
3957
]);
4058

41-
$expected = '<div class="radio-button-group foobar"><div id="radio_button_test" class="btn-group" data-field="#test"><button type="button" class="btn btn-primary" data-value="1">Yes</button><button type="button" class="btn btn-primary active" data-value="0">No</button><button type="button" class="btn btn-primary" data-value="3">Maybe</button></div></div><input type="hidden" id="test" class="test-class" name="test-widget-name">';
42-
$this->assertEquals($expected, $out);
59+
$this->assertMatchesSnapshot($out);
4360
}
4461

4562
public function testRenderWithButtonOptions()
@@ -57,8 +74,7 @@ public function testRenderWithButtonOptions()
5774
],
5875
]);
5976

60-
$expected = '<div class="radio-button-group"><div id="radio_button_w0" class="btn-group" data-field="#w0"><button type="button" class="btn btn-success active" data-value="1">Yes</button><button type="button" class="btn btn-danger" data-value="0">No</button><button type="button" class="btn btn-warning" data-value="3">Maybe</button></div></div><input type="hidden" id="w0" name="test-widget-name" value="1">';
61-
$this->assertEquals($expected, $out);
77+
$this->assertMatchesSnapshot($out);
6278
}
6379

6480
public function testRenderWithModel()
@@ -72,8 +88,7 @@ public function testRenderWithModel()
7288
'items' => Payment::$statuses
7389
]);
7490

75-
$expected = '<div class="radio-button-group"><div id="radio_button_payment-status_id" class="btn-group" data-field="#payment-status_id"><button type="button" class="btn btn-default" data-value="10">Active</button><button type="button" class="active btn btn-success" data-value="20">Inactive</button></div></div><input type="hidden" id="payment-status_id" name="Payment[status_id]" value="20">';
76-
$this->assertEquals($expected, $out);
91+
$this->assertMatchesSnapshot($out);
7792
}
7893

7994
public function testRegisterClientScript()
@@ -86,12 +101,10 @@ public function testRegisterClientScript()
86101
$widget->setView($view);
87102
$method->invoke($widget);
88103

89-
$expected = <<<JS
90-
jQuery(\'#radio_button_w1\').radioButtonGroup({\"activeState\":\"active btn btn-success\",\"defaultState\":\"btn btn-default\",\"buttons\":[]});
91-
JS;
92-
$this->assertStringContainsString($expected, VarDumper::dumpAsString($view->js));
104+
$this->assertMatchesSnapshot(VarDumper::dumpAsString($view->js));
93105
}
94106

107+
95108
public function testAssetRegister()
96109
{
97110
$view = Yii::$app->getView();
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php return '[
2+
4 => [
3+
\'e3874bece0aa0f30057a6863521a6247\' => \'jQuery(\\\'#radio_button_w1\\\').radioButtonGroup({\\"activeState\\":\\"active btn btn-success\\",\\"defaultState\\":\\"btn btn-default\\",\\"buttons\\":[]});\'
4+
]
5+
]';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<?php return '<div class="radio-button-group"><div id="radio_button_w0" class="btn-group" data-field="#w0"><button type="button" class="btn btn-success active" data-value="1">Yes</button><button type="button" class="btn btn-danger" data-value="0">No</button><button type="button" class="btn btn-warning" data-value="3">Maybe</button></div></div><input type="hidden" id="w0" name="test-widget-name" value="1">';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<?php return '<div class="radio-button-group"><div id="radio_button_payment-status_id" class="btn-group" data-field="#payment-status_id"><button type="button" class="btn btn-default" data-value="10">Active</button><button type="button" class="active btn btn-success" data-value="20">Inactive</button></div></div><input type="hidden" id="payment-status_id" name="Payment[status_id]" value="20">';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<?php return '<div class="radio-button-group"><div id="radio_button_test" class="btn-group" data-field="#test"><button type="button" class="btn btn-default" data-value="1">Yes</button><button type="button" class="active btn btn-success" data-value="0">No</button></div></div><input type="hidden" id="test" name="test-widget-name">';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<?php return '<div class="radio-button-group foobar"><div id="radio_button_test" class="btn-group" data-field="#test"><button type="button" class="btn btn-primary" data-value="1" data-show=".show-if-yes" data-hide=".show-if-no">Yes</button><button type="button" class="btn btn-primary active" data-value="0" data-show=".show-if-no" data-hide=".show-if-yes">No</button><button type="button" class="btn btn-primary" disabled data-value="3">Maybe</button></div></div><input type="hidden" id="test" class="test-class" name="test-widget-name">';

0 commit comments

Comments
 (0)