70

Somehow, through the magic of Angular, if you use ng-model and provide it a boolean, your checkbox will be checked if said boolean is true, and unchecked if false.

<input type="checkbox" ng-model="video.hidden">

While this alone is fairly baffling, I'm actually trying to reverse the checked state, because unlike the todo example where todo.done means the box gets checked, my model is more like todo.incomplete.

Unfortunately my first guess didn't work:

<input type="checkbox" ng-model="!video.hidden">

I'm in a position where the model has been dictated to me, so I can't change it and don't want to have to massage it on the client (because I'm sending client objects back to the server, since it's running in a trusted environment).

Update

This works in 1.3 and doesn't give you strings (1.2.xxx gave you strings instead of booleans):

<input type="checkbox" ng-model="video.hidden" ng-true-value="false" ng-false-value="true">
5
  • or just use a negation of whatever word you used to describe your model : video.shown : ? or use a function in your controller to set the value of another model when the checkbox is checked ... it is not a real problem in my opinion. Commented Dec 18, 2012 at 5:02
  • @camus The last thing I said was that I did not want to change the model, and I shouldn't have to. Of course it's not a real problem, but when a framework is touting ease of use, there's no reason why my first guess above shouldn't work. Commented Dec 18, 2012 at 14:06
  • 1
    using a function is not changing the model but adding a function to a controller. And no framework is a silver bullet. But this one is easily extentable , that's what you'll have to do anyway , write directives. Commented Dec 19, 2012 at 5:57
  • Your "ng-true-value" fix that you say "doesn't work right now" seems to work with the current angular code: plnkr.co/edit/tmpdYBiuzv9cy8JfRWtw?p=preview... Or am I misunderstanding what was broken with that? Commented Jan 7, 2015 at 1:07
  • @Troy It looks like it works in 1.3.6, but still does not work correctly in 1.2.27 (you get strings instead of booleans). Commented Jan 8, 2015 at 4:11

6 Answers 6

83

You can make that now without a need of custom directive, angular support ng-true-value and ng-false-value

https://docs.angularjs.org/api/ng/input/input[checkbox]

your example should work now <input type="checkbox" ng-model="video.hidden" ng-true-value="false" ng-false-value="true">

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

5 Comments

Problem with that solution is that the checkbox will still display the video.hidden value when displayed.
Looks like they fixed it in 1.3.
I see ng-true-value and ng-false-value, but the false value is not sent to the server. Maybe it's treated as not successful form control.
@SaeedNeamati , try adding value="true" ?
to do this in Angular Material - can refer this question stackoverflow.com/questions/53693740/…
23

I don't think there's a way to do this purely in the template. The most obvious way to accomplish this is create a new scope variable that's manually double-bound to your model value. So like:

<input type="checkbox" ng-model="videoShowing">

And in your controller:

$scope.videoShowing = !$scope.video.hidden;

$scope.$watch('video.hidden', function(value) {
  $scope.videoShowing = !value;
});
$scope.$watch('videoShowing', function(value) {
  $scope.video.hidden = !value;
}

You could almost just use one-way binding with an ng-change, but that doesn't quite work:

<input type="checkbox" ng-checked="!video.hidden" ng-change="???">

Because ng-change doesn't mix the current value into the local scope at all. If you were in a context where you had access to the NgModelController you could do something, but you'd need a custom directive for that. Wouldn't be hard to make an "inverted" attribute directive that modifies the NgModel's formatters and parsers. I'd suggest that if you need lots of inverted checkboxes.

Edit

For posterity, making an "inverted" attribute is super simple, might as well just do that. Making directives always seems like a pain at first, but it really is the Angular way.

someModule.directive('inverted', function() {
  return {
    require: 'ngModel',
    link: function(scope, element, attrs, ngModel) {
      ngModel.$parsers.push(function(val) { return !val; });
      ngModel.$formatters.push(function(val) { return !val; });
    }
  };
});

Might need to set the priority too, or "unshift" instead of push, to make sure these guys run after the built-in inputDirective ones.

2 Comments

what is ngModel argument here? is there any documentation about it? or it is a some type of DI magic?
The 4th argument to link mirrors whatever you require.
14

This seems to work

<input  type="checkbox" 
        ng-init = "video.checked = !video.hidden"
        ng-model ="video.checked"
        ng-change ="video.hidden = !video.checked"/>

It introduces a video.checked property that's the opposite of video.hidden and as soon as the checkbox changes the values are updated.

Example here: http://plnkr.co/edit/7HYht6ubkUUJQ0r3g16m?p=preview

5 Comments

Nice, this appears to work. Is the ng-init part necessary though? Inside of ng-change, do you not have access to the input read the checked state from it?
without ng-init when the view is compiled the value of video.checked would be undefined and checkboxes would be unchecked even when video.hidden is set to false which is when you want them checked. If you remove ng-init you would need to modify your videos objects from the controller and do the initialization from there.
So you don't have access to the target input inside of ng-change? Like, I couldn't say: ng-change ="video.hidden = !$element.checked"
One issue, which may not be a problem in your use case, is that the video.checked will not get updated automatically if the video.hidden changes programmatically. The solution by darkporter below is more robust.
good point. I'd personally write a custom directive and let it worry about updating the checkbox.
5

My solution uses a directive "negate", that you just add to the "input". It's simple, and there is no need to change the controller.

angular
    .module("<< your module >>")
    .directive('negate', [
        function () {
            return {
                require: 'ngModel',
                link: function (scope, element, attribute, ngModelController) {
                    ngModelController.$isEmpty = function(value) {
                        return !!value;
                    };

                    ngModelController.$formatters.unshift(function (value) {
                        return !value;
                    });

                    ngModelController.$parsers.unshift(function (value) {
                        return !value;
                    });
                }
            };
        }
    ]
);

Use it like this:

<input type="checkbox" negate ng-model="entity.nologin">

Comments

2

My Solution is Very simple: Just use ng-true-value / ng-false-value and set false to ng-true-value and true to ng-false-value which will reverse the functionality.

<input type="checkbox" ng-model="<<-- Your Model -->> " ng-true-value="false"
            ng-false-value="true">

Comments

0

I think the simplest solution to get the checked or unchecked value for a checkbox is by adding the ng-init directive inside the checkbox input element as follows:

<input type="checkbox" ng-init="video = false" ng-model="video" >

This enables the initial value of the checkbox to be false, were the state is unchecked. On submitting the form, if the checkbox is unchecked the value that returns (or console) will be false, instead of 'undefined', else upon checking it will be true.

if you want to add custom made values for the true or false state, you can use:

ng-true-value="'custom_true value'"

and

ng-false-value="'custom_false value'"

inside the input element. like :

<input type="checkbox" ng-init="video = false" ng-model="video" ng-true-value="'custom_true value'" ng-false-value="'custom_false value'">

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.