Search code examples
javascriptangularjsangularjs-ng-modelangularjs-ng-checked

Pre-checked inputbox are not being serialized


I have a simple code that list many colors and check if some has been chosen previamente by user(this is setted on code but in really its come from the database). When i submit the form, the pre-checked inputs don't are listed in array and if i uncheck some, this wont be removed from array.

const SampleApp = angular.module('SampleApp', [])

SampleApp.controller('sampleAppController', function($scope) {
    $scope.colors = ['red', 'green', 'blue', 'black', 'yellow', 'pink', 'white']
    $scope.preChecked = ['green', 'pink']
    $scope.user = { colors: [] }
    $scope.colorArr = []

    $scope.isUserColor = color => {
         return $scope.preChecked.some(uColor => color === uColor)
    }

    $scope.handleSubmit = () => {
        const filteredColors = $scope.colors.filter((color, index) => {
            return $scope.user.colors.some((uColor, uIndex) => {
                 return index === uIndex
            })
        })
        $scope.colorArr = filteredColors
    }    
})
<html lang="en" ng-app="SampleApp">
    <head>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
    </head>
    <div ng-controller="sampleAppController">
        <form ng-submit="handleSubmit()">
            <ul>
                <li ng-repeat="color in colors">
                    <input
                        type="checkbox"
                        name="{{color}}"
                        id="{{color}}"
                        ng-checked="isUserColor(color)"
                        ng-model="user.colors[$index]"
                        value="{{color}}"
                    >
                    <label for="{{color}}">{{color}}</label>
                </li>
            </ul>
            <button>Submit</button>
        </form>
        <div>{{colorArr}}</div>
    </div>
    </body>

</html>


Solution

  • The ng-model and ng-checked directives should not be used together1

    From the Docs:

    ngChecked

    Sets the checked attribute on the element, if the expression inside ngChecked is truthy.

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

    AngularJS ng-checked Directive API Reference


    Don't use ng-model and ng-checked together. Use ng-model for two-way binding, ng-checked for one-way binding.

    <ul>
       <li ng-repeat="color in colors">
            <input
                type="checkbox"
                name="{{color}}"
                id="{{color}}"
                ̶n̶g̶-̶c̶h̶e̶c̶k̶e̶d̶=̶"̶i̶s̶U̶s̶e̶r̶C̶o̶l̶o̶r̶(̶c̶o̶l̶o̶r̶)̶"̶
                ng-model="user.colors[$index]"
                ̶v̶a̶l̶u̶e̶=̶"̶{̶{̶c̶o̶l̶o̶r̶}̶}̶"̶
            >
            <label for="{{color}}">{{color}}</label>
        </li>
    </ul>
    

    Instead initialize the models from the controller:

    $scope.user = { colors: [] };
    $scope.user.colors = $scope.colors.map(c => $scope.preChecked.some(_ => _ == c));