Search code examples
htmlangularjsformscheckboxangularjs-ng-checked

ANGULARJS: Function I have in ng-checked directive runs infinitely


Trying to do something I thought is pretty simple but it's turning out to be pretty annoying. I'm just trying to have a function that runs when you click on a checkbox using the ng-checked directive.

This is the HTML:

    <div class="form-group">
        <label class="col-sm-2 control-label">Make Payment Optional</label>
        <div class="col-sm-4 center-checkbox">
            <input type="checkbox"
                   class="center-checkbox"
                   ng-model="formData.optionalPayment"
                   ng-checked="optionalPaymentCheckbox();"
                   validate-servererror="featured"/>
        </div>
    </div>

And this is the Angular:

if($scope.formData.optionalPayment === undefined) {
  $scope.formData.optionalPayment = TournamentConst.PAYMENT.OPTIONAL;
}

(This check is just for when I load the page for the first time.)

$scope.optionalPaymentCheckbox = function () {
  if($scope.formData.optionalPayment === TournamentConst.PAYMENT.OPTIONAL) {
    $scope.formData.optionalPayment = TournamentConst.PAYMENT.MANDATORY;
  } else {
    $scope.formData.optionalPayment = TournamentConst.PAYMENT.OPTIONAL;
  }
};

When I load the page, this ng-checked function runs infinitely. Is there something about the ng-checked directive I don't know, or some minor detail or forgot? Thanks in advance.


Solution

  • You are misunderstanding the intention of ng-checked. What you think it does is "execute this expression when the checkbox is checked" - an event handler directive.

    What it actually does is set the checked property based on the expression. This means it sets up a watch on the expression and evaluates it every digest. If the value changes, it sets or unsets the checked property accordingly.

    In fact, the documentation for ng-checked says this:

    Note that this directive should not be used together with ngModel, as this can lead to unexpected behavior.

    As @JB Nizet correctly pointed out, you can achieve the desired effect in your particular case by using ng-true-value and ng-false-value and removing ng-checked altogether.

    So your HTML becomes:

    <div class="form-group">
        <label class="col-sm-2 control-label">Make Payment Optional</label>
        <div class="col-sm-4 center-checkbox">
            <input type="checkbox"
                   class="center-checkbox"
                   ng-model="formData.optionalPayment"
                   ng-true-value="TournamentConst.PAYMENT.MANDATORY"
                   ng-false-value="TournamentConst.PAYMENT.OPTIONAL"
                   validate-servererror="featured"/>
        </div>
    </div>
    

    Then, in your controller, populate your TournamentConst object in the scope, so the template can see it:

    $scope.TournamentConst = TournamentConst;
    

    (or you can just populate the bits you need)

    Finally, get rid of the whole $scope.optionalPaymentCheckbox function. You will still need the code to set the default value, though.

    One last thing: It is confusing that the property is called optionalPayment, when it is really more like paymentType, but that is not related to the current problem.