Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a default value for radio button group #106

1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
sudo: false
language: node_js
before_install: npm install -g grunt-cli
node_js:
Expand Down
1 change: 1 addition & 0 deletions SpecRunner.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
<script src="spec/javascripts/keyExtractors.spec.js"></script>
<script src="spec/javascripts/serialize.nested.spec.js"></script>
<script src="spec/javascripts/serialize.spec.js"></script>
<script src="spec/javascripts/valueAssigners.spec.js"></script>
</head>
<body>
<div id="mocha"></div>
Expand Down
26 changes: 23 additions & 3 deletions apidoc.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,15 @@ You can register your own input readers, allowing you
to change how the data is read. To do this register
a callback function to an input type.

The default input reader for radio button is returning the value if button is checked or `null`.
```js
Backbone.Syphon.InputReaders.register('radio', function($el) {
return $el.prop('checked') ? $el.val() : null;
});
```

You can override the default behavior to return the value of the radio button independently of its status.

```js
Backbone.Syphon.InputReaders.register('radio', function(el){
return el.val();
Expand Down Expand Up @@ -264,8 +273,9 @@ extracted from the element. This is the last opportunity to prevent
bad data from getting serialized to your object.

The most common use of this is to ensure radio button groups are only
serialized by the one radio button that is selected, within the group. This
behavior is built in by default (see below).
serialized by the one radio button that is selected, within the group,
defaulting to `null` value if no button is selected. This behavior is
built in by default (see below).

### Assigning Your Own Validator

Expand Down Expand Up @@ -295,6 +305,16 @@ return a boolean (or truthy) value from the callback.
Return values of `true` or truthy will be valid and the assignment will occur. Return values
that are `false` or falsey will not be valid and the assignment will not occur.

### Overriding radio group output

Default will serialize a null value for a radio group if no button is selected. If you want a different behavior like no output if no radio button selected, you should override radio key assignment validator, like this:

```js
Backbone.Syphon.KeyAssignmentValidators.register("radio", function($el, key, value){
return $el.prop('checked');
});
```

### Assign A Key Assignment Validation Set

You can assign your own Key Validation Set by creating an instance of
Expand All @@ -315,7 +335,7 @@ just register and remove validations as needed.
There are two Key Assignment Validators built in to Syphon:

* default: everything is valid
* radio: only radio buttons that are selected are valid
* radio: only radio buttons that are selected are valid, or if a value different than `undefined` is returned by input reader. This should work for most cases, with radio button groups set to a `null` in case no buttons are selected.

## Handling Non-"input" Elements

Expand Down
12 changes: 11 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ By default, a checkbox will return a boolean value signifying whether or not it
<form>
<input type="checkbox" name="a">
<input type="checkbox" name="b" checked>
<input type="checkbox" name="c" indeterminate>
</form>
```

Expand All @@ -133,7 +134,8 @@ Backbone.Syphon.serialize(view);

{
a: false,
b: true
b: true,
c: null
}
```

Expand Down Expand Up @@ -164,6 +166,13 @@ Backbone.Syphon.serialize(view);
}
```

Serializing a form with no radio button checked will be serialized to :
```js
{
a: null
}
```

This behavior can be changed by registering a different set of Key Extractors, Input Readers, and Key Assignment
Validators. See the full
[API Documentation](https://github.com/marionettejs/backbone.syphon/blob/master/apidoc.md).
Expand Down Expand Up @@ -437,6 +446,7 @@ For more information on Key Assignment Validators, see the full
There some known limitations in Backbone.Syphon, partially by design and partially implemented as default behaviors.

* An input of type `checkbox` will return a boolean value. This can be overriden by replacing the Input Reader for checkboxes.
* Yo avoid circular references, care should be taken when using Backbone.Relational. See (#33)[https://github.com/marionettejs/backbone.syphon/issues/33].

## Building Backbone.Syphon

Expand Down
15 changes: 15 additions & 0 deletions spec/javascripts/deserialize.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,21 @@ describe('deserializing an object into a form', function() {
expect(this.result).to.be.false;
});
});

describe('and the corresponding value in the given object is null', function() {
beforeEach(function() {
this.view = new this.View();
this.view.render();
this.view.$('#the-checkbox').prop('checked', false);

Backbone.Syphon.deserialize(this.view, {chk: null});
this.result = this.view.$('#the-checkbox').prop('indeterminate');
});

it('should add an indeterminate attribute', function() {
expect(this.result).to.be.true;
});
});
});

describe('when deserializing into a button', function() {
Expand Down
44 changes: 41 additions & 3 deletions spec/javascripts/serialize.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,20 @@ describe('serializing a form', function() {
expect(this.result.chk).to.be.false;
});
});

describe('and the checkbox is indeterminate', function() {
beforeEach(function() {
this.view = new this.View();
this.view.render();
this.view.$('#the-checkbox').prop('indeterminate', true);

this.result = Backbone.Syphon.serialize(this.view);
});

it('should return an object with a value of null', function() {
expect(this.result.chk).to.be.null;
});
});
});

describe('when serializing a button', function() {
Expand Down Expand Up @@ -236,7 +250,7 @@ describe('serializing a form', function() {
this.$el.html(
'<form>' +
'<input type="radio" name="foo" value="foo">' +
'<input type="radio" name="foo" value="bar" checked>' +
'<input type="radio" name="foo" value="bar">' +
'<input type="radio" name="foo" value="baz">' +
'</form>'
);
Expand All @@ -246,11 +260,17 @@ describe('serializing a form', function() {
this.view = new this.View();
this.view.render();

this.result = Backbone.Syphon.serialize(this.view);
});

it('should return the value null when no selected radio button', function() {
var result = Backbone.Syphon.serialize(this.view);
expect(result.foo).to.equal(null);
});

it('should only return the value of the selected radio button', function() {
expect(this.result.foo).to.equal('bar');
this.view.$('[value=bar]').click();
var result = Backbone.Syphon.serialize(this.view);
expect(result.foo).to.equal('bar');
});
});

Expand Down Expand Up @@ -292,6 +312,24 @@ describe('serializing a form', function() {
});
});

describe('when given a form element with nested inputs', function() {
beforeEach(function() {
this.form = $(
'<form>' +
'<div>' +
'<input type="text" name="foo" value="bar">' +
'</div>' +
'</form>'
)[0];

this.result = Backbone.Syphon.serialize(this.form);
});

it('retrieves the inputs\' values', function() {
expect(this.result.foo).to.equal('bar');
});
});

describe('when given more than 1 form', function() {
beforeEach(function() {
this.View = Backbone.View.extend({
Expand Down
Loading