Search code examples
angularjscheckboxionic-frameworkangular-ngmodelangularjs-ng-checked

ng-checked not updating first time


I'm generating check boxes using ng-repeat, and their initial status can be checked or unchecked depending on if that information exists or not in the data. My problem is that altghough it shows their initial checked/unchecked status correctly, when I uncheck a box that has been 'pre-checked', the box physically unchecks but the model doesn't change. Then I check it again, and the model doesn't change but it's correct. Then I uncheck again, and it clears correctly in the model and works correctly from then on. I have been working on this problem for days and I'm totally stuck! Can anyone see if I'm doing something stupid? My feeling is that it's an initialisation problem but I'm too close to it to see now. Thanks!

<!-- if this is a checkbox to be drawn -->
<div ng-if="option.option_type=='checkbox'">
  <label class="item-checkbox-right">
  {{option.caption}} 
   <!-- handle multiple options -->

  <!-- if answered_options[n]weight exists, make option.ans = weight --></label>
  <ul ng-repeat="opti in questionpart.survey_answer[0].answered_options">
    <li style="list-style: none; display: inline">

    <!-- if option is set in the received data, set it in the model -->
      <div ng-if="opti.id == option.id">
        <div ng-init="option.ans = option.weight"></div>
      </div>
    </li>
  </ul>
  <label class="item-checkbox-right">
      <!-- show the checkbox and bind to option.ans-->
      <input class="checkbox-light" 
      type="checkbox" 
      name="{{questionpart.id}}" 
      ng-false-value="0" 
      ng-true-value="{{option.weight}}"
      ng-model="option.ans"
      ng-checked="option.ans==option.weight" />
  </label>
</div>

Solution

  • Here is a simple, but not pretty example. Using the default Angular directives for checkboxes never quite worked for me.

    app.js

    $scope.data = [{checkboxValue: 0}, {checkboxValue: 1}, {checkboxValue: 2}];
    $scope.dataCopy = angular.copy( $scope.data );
    
    $scope.setCheckboxValue = function( checkbox, index ) {
        checkbox.checkboxValue = checkbox.checkbox ? $scope.dataCopy[index].checkboxValue : 0;
    }
    
    $scope.parseCheckboxes = function() {
        for( var i = 0, len = $scope.data.length ; i < len ; i++ ) {
            $scope.data[i].checkbox = $scope.data[i].checkboxValue > 0 ? true : false;
        }
    }
    
    $scope.parseCheckboxes();
    

    Basically what I do at the controller is handling the logic for checkboxes all by myself. I create a copy of the array so that when we toggle from false to true, we get the initial value.

    I make an additional key in every object which keeps track of the status of the checkbox (true or false) so it doesn't interfere with the actual value.

    The initial marking is done by parsing the array of objects and setting all the checkboxes to true or false depending on their values.

    html

    <body ng-controller="MainCtrl">
        <label ng-repeat="d in data track by $index">
            <input type="checkbox" ng-model="d.checkbox" ng-change="setCheckboxValue(d, $index )" />
            {{d.checkbox}}
            {{d.checkboxValue}} 
            <br>
        </label>
    </body>
    

    The html part is pretty self explanatory.

    There probably is better ways to solve this, but this is the solution I came up with. Not pretty, but it works.