trvo
trvo

Reputation: 685

AngularJS Directives emulate radio button

I would like to build a directive which emulates radio button behaviour, this seems fairly trivial if you control the radio buttons externally, but I want to do it so that the radio buttons control themselves. This means they become self-contained bits of code.

Angular Directives are not my strong point, but here is what I have come up with so far:

HTML:

<test-radiobutton name="test" value="1" label="Testing" checked="false"></test-radiobutton>
<test-radiobutton name="test" value="2" label="Testing 2" checked="false"></test-radiobutton>

Template:

<div>
    <div class="test_radiobutton_box" ng-class="{'checked': checked}" ng-click="toggleChecked()"></div>
    <div class="test_radiobutton_label">{{ label }}</div>
</div>

And the JS:

.directive("testRadiobutton", function() {
    return {
        restrict: "AE",
        scope: {
            label: "@label",
            name: "@name",
            value: "@value",
            checked: "=checked"
        },
        templateUrl: "../../test_components/test-radiobutton/test-radiobutton.html",
        controller: function ($scope) {
            $scope.toggleChecked = function () {
                $('test-radiobutton[name='+$scope.name+']').attr("checked", "false");

                $('test-radiobutton[name='+$scope.name+'][value='+$scope.value+']').each(function (index) {
                    $(this).attr("checked", "true");
                });
            };
        },
        link: function(scope, element, attributes){

        }
    };
});

The problem is that the other radio buttons aren't deselecting when you select a new one with the same name, the jQuery is looping through the elements correctly and finds the other elements (tested using .each()) but doesn't toggle their values.

Obviously I'm not doing this how Angular intends so how would I do this?

EDIT - to reflect using a service (still not working)

New controller within directive uses my new radio button service.

controller: function ($scope, RadioButtonService) {
    $scope.toggleChecked = function () {
        RadioButtonService.selectRadio($scope.name, $scope.value);
    };
},

And my service:

angular.module("test_components.testRadiobutton.service", [])
.factory("RadioButtonService", function () {
    return {
        deselectAllRadios: function (radio_name) {
            $('test-radiobutton[name='+radio_name+']').each(function (index) {
                console.log("deselecting");
                angular.element($(this)).scope().checked = false;
            });
        },
        selectRadio: function (radio_name, radio_value) {
            this.deselectAllRadios(radio_name);
            $('test-radiobutton[name='+radio_name+'][value='+radio_value+']').each(function (index) {
                console.log('test-radiobutton[name='+radio_name+'][value='+radio_value+']');
                angular.element($(this)).scope().checked = true;
            });
        }
    };
});

The console outputs correctly, manually referencing the elements with jQuery works too but the checkbox value just won't change.

Upvotes: 1

Views: 1928

Answers (2)

trvo
trvo

Reputation: 685

I ended up making the directive accept an object of radio buttons, then I used ng-repeat to render them, that gave my directive's controller access to all of the radios, from there onwards it was a simple case of using the clicked button's $index to toggle the $scope.radios[i].isChecked value depending on whether it was the one clicked or not.

This method is extremely simple, not sure why I tried it my original way.

Upvotes: 1

user50992
user50992

Reputation: 201

I know a two ways of how I would do this. I recommend the first one.

1. Create service

Create a simple factory service which is part of your module. Let it manage your radio buttons and groups of them. I suggest this over the next method.

2. Access scope of the other element

You can access scope of another directive like this:

angular.element($("#your-element")).scope();

You just have to iterate through all of your selected objects then access the scope and change the value. It shouldn't be too hard.

Upvotes: 1

Related Questions