Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: Binding boolean value to radio button such that it updates model to false on uncheck event

In my AngularJS application, I am displaying contacts data in a grid. My typical contacts JSON looks like as below ...

[
    { type: "IM", value: "mavaze123", default: true },
    { type: "IM", value: "mvaze2014", default: false },
    { type: "IM", value: "mavaze923", default: false },
    { type: "IM", value: "mvaze8927", default: false },
    { type: "Email", value: "[email protected]", default: true },
    { type: "Email", value: "[email protected]", default: false } 
]

The last property 'default' is actually a radio button, selection of which should alter the original default value of the corresponding contact type in above JSON. There can be one default from each type of contact i.e. we can group radio buttons based on the contact type.

<div ng-repeat="contact in contacts">
    <div>{{contact.type}}</div>
    <div>{{contact.value}}</div>
    <div><input type="radio" name="{{contact.type}}" ng-model="contact.default" ng-value="true"/></div>
</div>

Note: The above code is not the exact one, but approximately same, as it will appear inside a custom grid component.

Now when I load my view/edit form page with above JSON, it correctly shows the radio state of all contacts. The problem comes, after page load, when user selects another contact as default. This actually changes the model value of default to true for newly selected contact however the model value of original default contact still remains true, even though its radio state changes to uncheck/blur (because they are having same 'name' value).

I thought to write a directive, but I am unable get it triggered on radio on-blur/uncheck event.

There are various posts on binding boolean values to radio buttons, but I am unable to get it work in my scenario, as I want to update model values for individual radio button in a radio group. See there is no single model representing a radio group.

Original State of radio buttonsModel changes on selection of radio buttonPrevious model remains unchanged on selection of other radio button

like image 722
mavaze Avatar asked Jan 04 '14 05:01

mavaze


2 Answers

I think you should change your design to separate the contacts from contactTypes and store the key to the default contact in contact type.

In your current design, there are duplicated values for default and that's not the desired way to work with radio.

$scope.contacts = [
        { type: "IM", value: "mavaze123" },
        { type: "IM", value: "mvaze2014" },
        { type: "IM", value: "mavaze923" },
        { type: "IM", value: "mvaze8927" },
        { type: "Email", value: "[email protected]" },
        { type: "Email", value: "[email protected]" } 
   ];

    $scope.contactTypes = {
        "IM": { default:"mavaze123"}, //the default is contact with value = mavaze123
        "Email": { default:"[email protected]"}
   };

You Html:

<div ng-repeat="contact in contacts">
            <div>{{contact.type}}</div>
            <div>{{contact.value}}</div>
            <div><input type="radio" name="{{contact.type}}" ng-model="contactTypes[contact.type].default" ng-value="contact.value"/></div>
        </div>

DEMO

I assume that the key of contact is value, you could use an Id for your contact.

like image 126
Khanh TO Avatar answered Sep 18 '22 14:09

Khanh TO


I added an attribute directive in my input statement ...

<div ng-repeat="contact in contacts">
    <div>{{contact.type}}</div>
    <div>{{contact.value}}</div>
    <div><input type="radio" name="{{contact.type}}" ng-model="contact.default" ng-value="true" boolean-grid-model /></div>
</div>

And my custom directive ...

myModule.directive('booleanGridModel') {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, elem, attrs, controller) {
           var radioSelected = scope.$eval(attrs.ngModel);
           if(radioSelected) {
               var selectedContact = scope.contact;
               _.each(scope.contacts, function(contact) {
                  if(contact.type === selectedContact.type) {
                      _.isEqual(contact, selectedContact) ? contact.default = true : contact.default = false;
                  }
               });
           }
       }
    };
}
like image 20
mavaze Avatar answered Sep 19 '22 14:09

mavaze