0

I want to be able to have a list of items and to select one using a checkbox:

<div data-ng-repeat="device in devices">
    <div class="col-sm-offset-2 col-sm-10">
        <div class="checkbox">
            <label>
                <input type="checkbox"> {{ device.name }}
            </label>
        </div>
    </div>
</div>

If this can be done using a custom directive that would also be cool!

So the idea, that when a checkbox is checked the device would go into an ng-model and all the other checkboxes would be disabled.

I have a feeling there needs to be a custom model created, something like:

devices = [{
     name: "LED",
     checked: false,
     id: "98"
  },{
     name: "LED 2",
     checked: false,
     id: "8"
  },{
     name: "LED 3",
     checked: false,
     id: "78"
  }]

Just need some function to fire each time one checkbox is checked.

I expect that it can be done with a ng-click on the checkbox? And a two way data binding on the model for canBeChecked

devices = [{
         name: "LED",
         checked: false,
         id: "98",
         canBeChecked: true
      },{
         name: "LED 2",
         checked: false,
         id: "8",
         canBeChecked: true
      },{
         name: "LED 3",
         checked: false,
         id: "78",
         canBeChecked: true
      }]
7
  • Why a checkbox and not a radio button? Radio buttons are better for mutually exclusive options. Commented Apr 10, 2014 at 10:10
  • I know, but they don't have the same look and feel as checkboxes, they would be the better option, I just don't want to use them :) Commented Apr 10, 2014 at 10:12
  • That goes against best practices. What do you mean by "they don't have the same look and feel"? Commented Apr 10, 2014 at 10:28
  • @GregL: "best practices" are often ignored by the people in charge. As an engineer, you are told to build a feature and that's the end of story. I was charged with doing the very same thing not long ago, and it made no sense to quarrel with the boss :). Commented Apr 10, 2014 at 10:32
  • @GregL it does, but when you fill out a form, you tick one box don't you? (more often then not). And unfortunately my app is meant for the most basic of computer users (95% of the country :P) Commented Apr 10, 2014 at 10:39

3 Answers 3

4

Iterate over your collection and display a checkbox for each:

<div ng-repeat="device in devices">
    <label>
        {{ device.name }}
        <input type="checkbox" ng-model="device.checked" ng-click="change(device)">
    </label>
</div>

Note that the checkbox also has the ng-click directive. This is what you want to trigger each time a checkbox is clicked. The triggered function clears all checkboxes and only checks the clicked one. The checkboxes should now behave like radio buttons.

Your controller might look like this:

app.controller("MyCtrl", ["$scope", function($scope) {
    $scope.devices = [{
        name: "LED",
        checked: false
    }, {
        name: "LED 2",
        checked: false
    }, {
        name: "LED 3",
        checked: false
    }];

    $scope.change = function(device) {
        angular.forEach($scope.devices, function(item) {
            item.checked = false;
        });
        device.checked = true;
    };
}]);

It is not necessary to create the canBeChecked property you mention.

Here's the full working example: http://jsfiddle.net/zxdr8/

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

5 Comments

Using ng-change is more semantically correct, though ng-click probably works in most modern browsers.
I know, and I agree. However, ng-change allows a checkbox to be unchecked too. If the OP wants a radio-like behaviour, it makes sense to disallow unchecking. This is why I used ng-click instead of ng-change.
I have to say, I'm liking this one more, purely because you can't un-check a checkbox!
Funnily enough, come to think of it, I did this in an earlier project, only difference is, I was using Knockout not Angular, nd I understand that better (maybe not for long though :) )
Can you up vote my question just so it is 0, thanks, no one said why they down voted it....
1

If you must use checkboxes, here is how you would do it.

Markup:

<div data-ng-repeat="device in devices">
    <div class="col-sm-offset-2 col-sm-10">
        <div class="checkbox">
            <label>
                <input type="checkbox" ng-model="device.checked" ng-change="checkDevice(device)"> {{ device.name }}
            </label>
        </div>
    </div>
</div>

Controller:

$scope.devices = [{
     name: "LED",
     checked: false,
     id: "98"
  },{
     name: "LED 2",
     checked: false,
     id: "8"
  },{
     name: "LED 3",
     checked: false,
     id: "78"
  }];

$scope.checkDevice = function (device) {
    for (var i = 0, len = $scope.devices.length; i < len; ++i) {
        if ($scope.devices[i] !== device)
             $scope.devices[i].checked = false;
    }
});

Comments

1

Your checked and canBeChecked properties seems like merely an UI thing. In my opinion, you should not be creating a custom data models and duplicating unnecessary properties just to do that. Believe me, I did things like that too when started using Angular, but there are much better ways.

Consider storing selected data in other location (model, service, controller, whatever). And maybe if you can store just an ID (primitive property), you can do your "checkbox-radio-like-element" like this:

<div ng-repeat="device in devices">
  <label>
    <input type="checkbox" ng-true-value="{{device.id}}" ng-false-value="" ng-model="some.storage">
    {{device.name}}
  </label>
</div>

And thats all you need, no background code needed. When Angular team implements interpolation support for ngTrueValue and ngFalseValue directives, you will be able to store the whole objects and reset model to e.g. null.

Comments

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.