0
votes

I have a strange scenario where my checkbox is not being ticked using Angular (1.5). I've checked in chrome Batarang and it looks okay yet my checkbox is not being ticked when clicking on my link!?

I have an array that's displayed using ng-repeat. Within the ng-repeat I have a checkbox and a hyperlink I want to control the checkbox with.

Can anyone see why the hyperlink is not checking the checkbox?

Many thanks,

Markup

<tr ng-repeat="o in vm.myArray track by o.Id"> 
  <td>

      <!-- This works (changes the checkbox to checked)-->
      <a href ng-click="o.Highlight=true">Just to test it (this works)</a> 

      <input type="checkbox" ng-model="o.Highlight" ng-click="vm.highlight(vm.myArray.Days, o.Name);" style="width: 15px" />

      <!-- This fails (I'm expecting it to check the checkbox) -->
      <a href ng-click="vm.highlight(vm.myArray.Days, o.Name)">
          {{o.Name}} 
      </a>
  </td>

</tr>

All this method is doing is iterating through an array of objects which have a property "Highlight" (boolean) which is then used to control stuff in the UI. I want the Highlight property to control whether the checkbox is checked or not.

Watching what this method does in the Chrome batarang the Highlight property is set correctly which in turn should toggle the checkbox but for some reason it isn't.

Highlight method in controller

(function() {
    "use strict";

    angular.module("bla").controller("homeCtrl", ["stuff", function (stuff) {
    var vm = this;
    vm.highlight = highlight;

    // Iterate through array and if the fieldToHighlight matches the item.Name then toggle the item as highlighted.
    function highlight(collection, fieldToHighlight) {

        for (var i = 0; i < collection.length; i++) {
            var element = collection[i];

            if (element.Items != null) {
                for (var counter = 0; counter < element.Items.length; counter++) {
                    var item = element.Items[counter];

                    if (fieldToHighlight == item.Name) {
                        if (item.Highlight) {
                            item.Highlight = false;
                        }
                        else {
                            item.Highlight = true;
                        }
                    }
                }
            }
        }
    }

Update after comments

Angular plugin for Chrome

This shows the Highlight property is set to false onload. When I click the test hyperlink the Highlight property is correctly changed to true.

angular plugin for chrome showing property correct data type

Update 2 - shows chrome debugging is setting the value correctly

This debugged point was when I clicked the hyperlink that fails.

code being debugged showing the highlight is working even though the ui is now updating

Update after comments (13th december 2016)

Comments in the code

<tr ng-repeat="o in vm.myArray track by o.Id">
    <td>
      <!-- checkbox -->
      {{o.Highlight}}
      <!-- clicking this changes the echo'ed variable immediately above but doesn't toggle the UI behaviour that relies on o.Highlight -->
      <input type="checkbox" ng-click="vm.highlight(o);" ng-model="o.Highlight" />

      <!-- name -->
      <!-- clicking this toggles the right behaviour in the UI which relies on the o.Highlight property but it doesn't toggle the checkbox to be checked or unchecked -->
      <a href ng-click="vm.highlight(o)">{{o.Name}}</a>
    </td>
</tr>
1
To checked your checkbox you need to try with $scope some like $scope.Items[0].Highlight=true; - Gautam Patadiya
okay but why would the test link work then and inside the highlight function the item.Highlight is working correctly. - Martin
Where does the "criteria" variable come from? It seems out of scope... - Vi100
In order to check it pragmatically you need to set like it. So $scope can find it. - Gautam Patadiya
@GautamPatadiya I'm using controllerAs: 'vm' so there's no "$scope" - Martin

1 Answers

0
votes

I have few questions and few answers for you :-)

  1. In the ng-repeat, the array vm.myArray is being used whereas, to the vm.highlight() method vm.myArray.Days is being passed where vm.myArray is used like an object in the latter. The question is why you have used myArray as array in ng-repeat and as object in the click event.
  2. Also inside this method, o.Name being passed is checked with the deep level property such as vm.myArray.Days[0].Items[0].Name. Why there is two different format for the comparison.

You should have posted the myArray collection to answer these questions.

Anyways, if I treat myArray is an array and not an object (assuming your ng-repeat works correctly but not the click events), I can suggest the below answers (all same, but kind of different way it represents).

Answer 1:

As you tried with the first link above (which works for you), you can try the toggle o.Highlight=!o.Highlight instead of o.Highlight=true as below, if all you want is just a toggle.

<a href ng-click="o.Highlight=!o.Highlight">Just to test it (this works)</a> 

Answer 2:

Still if you want the same toggle but with the function inside the controller to do other tasks, you can do as below,

<a href ng-click="vm.highlight(o)">{{o.Name}}</a>

function highlight(obj) {
   obj.Highlight = !obj.Highlight;
}

Answer 3:

But if you want to check the property Name against the array, then you can do as below.

<a href ng-click="vm.highlight2(vm.myArray, o)">{{o.Name}}</a>

function highlight2(collection, obj) {
  for (var i = 0; i < collection.length; i++) {
    var item = collection[i];
    if (obj.Name == item.Name) {
       obj.Highlight = !obj.Highlight;
    }
  }
}

Note: If you have an invalid array or different structure, then the above 3 answers may not work for you where you have to post the sample data of vm.myArray

Sample snippet:

(function() {
    "use strict";
    angular.module("bla", []);
    angular.module("bla").controller("homeCtrl", [ function () {
    var vm = this;
    vm.highlight = highlight;
    vm.highlight2 = highlight2;
      
    vm.myArray = [{Id: 1, Name: 'Item 1'}, {Id: 2, Name: 'Item 2'}, {Id: 3, Name: 'Item 3'}];

    // Iterate through array and if the fieldToHighlight matches the item.Name then toggle the item as highlighted.
    function highlight(obj) {
       obj.Highlight = !obj.Highlight;
    }
      
    function highlight2(collection, obj) {
      for (var i = 0; i < collection.length; i++) {
        var item = collection[i];
        if (obj.Name == item.Name) {
           obj.Highlight = !obj.Highlight;
        }
      }
    }
      
    /*function highlight(collection, fieldToHighlight) {

        for (var i = 0; i < collection.length; i++) {
            var element = collection[i];

            if (element.Items != null) {
                for (var counter = 0; counter < element.Items.length; counter++) {
                    var item = element.Items[counter];

                    if (fieldToHighlight == item.Name) {
                        if (item.Highlight) {
                            item.Highlight = false;
                        }
                        else {
                            item.Highlight = true;
                        }
                    }
                }
            }
        }
    }*/
      
}]);
  
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="bla">
<table ng-controller="homeCtrl as vm">
  <tr ng-repeat="o in vm.myArray track by o.Id"> 
   <td>

      <!-- This works (changes the checkbox to checked)-->
      <a href ng-click="o.Highlight=!o.Highlight">Just to test it (thistoggle works)</a> 

      <input type="checkbox" ng-model="o.Highlight" ng-click="vm.highlight(o);" style="width: 15px" />
      Link 1: 
      <a href ng-click="vm.highlight(o)">
          {{o.Name}} 
      </a>&nbsp;
      Link 2: 
      <a href ng-click="vm.highlight2(vm.myArray, o)">
          {{o.Name}} 
      </a>
   </td>

  </tr>
</table>
</div>