1

I am trying to have radio buttons controlling boolean properties of external objects through getters and setters.

In the following example, there are multiple Person, but only one can be happy. One of them is already happy. I want to control which one is happy through radio buttons.

Therefore, I created a template with a radio input, but I can't bind it to person.happy, as I don't have access to this property (suppose Person is a third-party library).

In order to bind something to the input, I created a dumb controller, to provide a default value (the Person value), and propagate changes to the real variable (in short, call the setter). I can't seem to get things right.

var app = angular.module('app', []);

// Person constructor ; happy is a private member
function Person(name, isHappy) {
  var happy = isHappy;
  this.name = name;
  this.getHappy = function() { return happy; }
  this.setHappy = function(value) { happy = value; }
}

// Inject a person list in the scope
app.controller('PeopleCtrl', function($scope) {
  $scope.people = [
    new Person('Alice', true),
    new Person('Bob', false),
    new Person('Carol', false)
  ];
});

// Template to display one person + happiness controller
var humanTemplate = [
  '<div><label>',
  '<input type="radio" name="group" ng-model="me.happy" ng-change="me.toggle()" value="{{ !me.happy }}">',
  '<span>{{ person.name }} is {{ me.happy ? "happy" : "sad" }}</span>',
  '</label></div>'
].join('');

// Directive to display one person
app.directive('human', function() {
  return {
    restrict: 'E',
    template: humanTemplate,
    scope: {
      person: '='
    },
    controllerAs: 'me',
    controller: function($scope) {
      var me = this;
      me.happy = $scope.person.getHappy();
      me.toggle = function() {
        console.log(me.happy);
        $scope.person.setHappy(me.happy);
      };
    }
  };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.5/angular.min.js"></script>
<div ng-app="app" ng-controller="PeopleCtrl">
  <human ng-repeat="p in people" person="p"></human>
</div>

I would have thought ngChange would be tied to the checked state on radio and checkboxes (would have been somehow logical), but there are symptoms telling me otherwise:

  • ngChange is not fired for the previously checked radio
  • ngChange is not fired more than once (I got it to fire twice when messing with the input value attribute)

I may be mistaken since I am a beginner, but it looks like ngChange is not what I want.

What do you think would be a good solution for this problem? Do I need to write a parent controller to manage manually the deactivation of some items when the other get activated?

1 Answer 1

1

I think (at least what I see from demo) you use radio buttons with different purpose.

Radio buttons works in groups where each button has shared ng-model. In your case human directive has own scope and therefore each radio button has own model a.e. stand-alone, that breaks radio buttons concept and usage.

Change to classic checkbox type="checkbox" and everything will work properly

Demo Plunker

Sign up to request clarification or add additional context in comments.

2 Comments

I really want them to behave like radio buttons, with only one being checked at any given time, that's why they share their name attribute. If I understand well, I cannot have this uniqueness without implementing the toggle() method in a parent controller like PeopleCtrl, regardless of whether I use radio or checkbox?
@GnxR I really want them to behave like radio buttons, with only one being checked at any given time, that's why they share their name attribute. all of them should have same ng-model. So u can create it in controller and pass to directives

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.