Search code examples
javascriptangularjsradio-buttonangularjs-ng-repeatdeselect

AngularJS - ng-repeat radio buttons with deselect/unselect


I'm trying to create an ng-repeat block for radio buttons. I need the buttons to be deselectable.

Here is an example of the ng-repeat block:

<div ng-repeat="role in roles" class="checkbox checkbox-inline checkbox-primary">
 <input id="{{ role.Value }}" ng-model="$parent.roleSelected" class="styled" type="radio" 
   name="{{ role.Group }}" value="{{ role.Value }}" />
 <label for="{{ role.Value }}">{{ role.Name }}</label>
</div>

Edit: The feature of using a deselectable radio button by clicking the same button was given as a requirement by the customer. This question is about how it can be done, not whether it should be done.


Solution

  • I did some searching and found that the deselection of radio buttons is not that simple. Below is a question that somewhat addressed it, but it doesnt seem to work when done in an ng-repeat block: AngularJs. Is it possible to deselect HTML “radio” input by click?

    Here is how i solved the problem. First I setup the ng-repeat as such:

    <div ng-repeat="role in roles" class="checkbox checkbox-inline checkbox-primary">
     <input id="{{ role.Value }}" ng-model="$parent.roleSelected" class="styled" type="radio" 
       name="{{ role.Group }}" value="{{ role.Value }}"  ng-click="clickRole($event)" />
     <label for="{{ role.Value }}">{{ role.Name }}</label>
    </div>
    

    In the controller, I have two methods. One for the ng-click and one that watches for changes on the ng-model. I also have an array ($scope.rolesSelected) that keeps track of the selected roles. (I had multiple ng-repeat blocks on the page, some were radio, some were checkboxes).

    When a radio (or checkbox) is clicked, it does the clickRole() function which adds the roleSelected to the rolesSelected array.

    $scope.clickRole = function (event) {
        if (event.target.type != 'radio') { // for checkboxes
            addOrRemoveFromArray($scope.rolesSelected, event.target.value);
        } else { // for radio - uncheck radio if selection was removed
            var addedRole = addOrRemoveFromArray($scope.rolesSelected, event.target.value);
            if (!addedRole) {
                event.target.checked = false;
            }
        }
    }
    

    The addOrRemoveFromArray() function simply adds the given value if not already in the array, otherwise removes it. This is to allow removal of selected role when radio button clicked twice (once to add, second to remove it).

    function addOrRemoveFromArray(array, value) {
        if (typeof value == 'undefined') { return; }
        var index = array.indexOf(value);
        if (index > -1) {
            array.splice(index, 1);
            return false;
        } else {
            array.push(value);
            return true;
        }
    }
    

    Up until here, it handles the addition of the role and the removal of the role when deselected. (also handles add/remove for checkboxes). But for radios, when selecting a different role, it doesnt remove the previous one. So needed another watch() function for that on the ng-model.

    $scope.$watch('roleSelected', function (newValue, oldValue) {  
      removeFromArray($scope.rolesSelected, oldValue); 
    });
    

    Finally with this I was able to handle the changing of roles on the radio buttons as well as deselection.

    This took me a good amount of time to figure out so I'm posting on here in case anyone else comes across similar situation. Thanks!