theironcook / Backbone.ModelBinder

Simple, flexible and powerful Model-View binding for Backbone.
1.42k stars 159 forks source link

ModelBinder incorrectly handles true/false radio button values #165

Open elwayman02 opened 11 years ago

elwayman02 commented 11 years ago

ModelBinder is unable to correctly check a radio button if its value is a boolean.

The problem manifests on line 397 of ModelBinder.js:

case 'radio':
    el.prop('checked', el.val() === convertedValue);
    break;

Let's say the element looks like this:

<input name="someRadio" type="radio" value="true" />

el.val() returns "true" as a string, but the value on the model is an actual boolean (because that's how the data is truly represented). So "true" === true evaluates to false and the radio button is not checked.

I could write a converter to force the value to be converted to a string (which I'm going to have to do in the meantime), but I think the proper solution would be to have ModelBinder check to see if convertedValue is a boolean and convert it to a string in the case of a radio button.

Something like this:

case 'radio':
    if (convertedValue === true) { convertedValue = 'true'; }
    else if (convertedValue === false) { convertedValue = 'false'; }
    el.prop('checked', el.val() === convertedValue);
    break;
theironcook commented 11 years ago

@elwayman02 - this is strange. I just ran a quick test and things appear to be working fine...

Here are some snippets from my quick test - have you tried with the latest? I'm using Chrome with JQuery 1.10.2. I wonder if there is a browser difference?

     Is Animal?<br>
    <input type="radio" name="isAnimal" value="true" /> True <br/>
    <input type="radio" name="isAnimal" value="false" /> False

    this._modelBinder.bind(this.model, this.el, {isAnimal: '[name=isAnimal]'});

    this._model.on('change:isAnimal', function(){console.log('isAnimal changed to ', m.get('isAnimal'))});

    this.model.set('isAnimal', true);
    this.model.set('isAnimal', false);
elwayman02 commented 11 years ago

I tried it on Chrome w/ jQuery 1.10.2 and ModelBinder 1.0.5, so I'm not sure how it worked for you. I had to write the following custom converter to get it to work.

converter: function(direction, value) {
    if (_.isEqual(direction, ModelBinder.Constants.ViewToModel)) {
        return value === "true";
    } else if (value === true) {
        return "true";
    } else if (value === false) {
        return 'false';
    }
    return '';
}
theironcook commented 11 years ago

I'll leave this issue open. If anyone else has the same issue I'll introduce the change to the Backbone.ModelBinder. Sorry - I just can't replicate the issue.

chris-h-sg commented 10 years ago

I'm having this problem as well. Backbone 1.1, ModelBinder 1.0.5. My radio buttons have true and false in their value attributes. The value in my model is a boolean.

Without a converter, no radio button is selected. With this converter (Coffeescript), it works:

converter: (dir, value) -> "" + value
cbmayer commented 10 years ago

I just experienced the same problem. I used thrar's solution to overcome it. I'm using ModelBinder 1.0.5 and Backbone 1.1.2.

dbrin commented 9 years ago

Checkboxes bind fine to a boolean model attribute but radio buttons do not. They seem to set the value attribute as string and are not checked when model value is set true.

technikhil314 commented 9 years ago

I have face the same issue, because I had given checked attribute to a radio button in group to make it checked by default. I have found that in version v1.0.5 on line 303 instead of if(el.attr('type') === 'radio' && el.attr('checked')) it should be if(el.attr('type') === 'radio' && el.is(':checked')) Since I have added checked attribute to the first radio button from the "radio button group" to make checked by default when view is rendered, the function always return the first radio button element itself.i.e. it will always return the radio button from group that has checked attribute.

akotian commented 9 years ago

I found that, if your model returns and integer value, which is used to populate the radio buttons value the ModelBinding does not select the radio button value. Providing a converter like

var radioButtonConverter = function(direction, value) {
  if (_.isEqual(direction, Backbone.ModelBinder.Constants.ViewToModel)) {                                                                                                                                                         
    return parseInt(value);
  } else {
    return value.toString();
  } 
};

seemed to work for me

mgrollins commented 5 years ago

The way to get Boolean "value" settings to work, is to "v-bind" to the value so that Vue treats it as a JavaScript expression rather than a string.

As mentioned at the "Passing a Number" section of the guide: "

https://vuejs.org/v2/guide/components-props.html#Passing-a-Number

elwayman02 commented 5 years ago

I think you might be posting in the wrong thread @mgrollins...

boussou commented 5 years ago

Mr Trolling ? ;-)