3

Once upon a time this was working but somehow it's broken. I want to be able to produce checkboxes using ng-repeat to get as many checkboxes as required based on stored data and use these to filter through a table produced.

Additionally I don't want identical values for the checkboxes to be repeated.

I have made a plnkr with the code.

<div class="row">
    <label data-ng-repeat="x in projects">
        <input
        type="checkbox"
        data-ng-true-value="{{x.b}}"
        data-ng-false-value=''
        ng-model="quer[queryBy]" />
        {{x.b}}
    </label>
</div>

http://plnkr.co/edit/RBjSNweUskAtLUH3Ss6r?p=preview

So in summary.

  1. Checkboxes to filter Ref.

  2. Checkboxes to be unique.

  3. Checkboxes to be made based off ng-repeat using Ref.

2 Answers 2

2

Okay, here's how to do it.

First, let's add a couple of lines of CSS in your to make sure all the checkboxes are visible:

<style>
  .row { margin-left: 0px }
  input[type=checkbox] { margin-left: 30px; }
</style>

Next, add the following lines to your controller:

app.filter('unique', function() {

  return function (arr, field) {
    var o = {}, i, l = arr.length, r = [];
    for(i=0; i<l;i+=1) {
      o[arr[i][field]] = arr[i];
    }
    for(i in o) {
      r.push(o[i]);
    }
    return r;
  };
})

  app.controller("maincontroller",function($scope){
    $scope.query = {};
    $scope.quer = {};
    $scope.queryBy = '$';
    $scope.isCollapsed = true;
    $scope.selectedRefs = [];

  $scope.myFilter = function (item) { 
    var idx = $scope.selectedRefs.indexOf(item.b);
    return idx != -1; 
  };

  $scope.toggleSelection = function toggleSelection(id) {
    var idx = $scope.selectedRefs.indexOf(id);
    if (idx > -1) {
      $scope.selectedRefs.splice(idx, 1);
    }
    else {
      $scope.selectedRefs.push(id);
    }
  };

Phew.

For some reason, your Plunkr's version of AngularJS didn't recognise the unique attribute, so I added one to your controller.

Finally, change your html to this:

<div class="row">
    <label data-ng-repeat="x in projects | unique:'b' | orderBy:'b'" >
        <input
        id="x.b"
        type="checkbox"
        ng-click="toggleSelection(x.b)"
        ng-init="selectedRefs.push(x.b)"
        ng-checked="selectedRefs.indexOf(x.b) > -1" />
        {{x.b}} 
    </label>
</div>

... and your ng-repeat to this...

<tr ng-click="isCollapsed = !isCollapsed" ng-repeat-start="x in projects | filter:myFilter | orderBy:orderProp">

If you're interested in knowing how this works, add these lines:

<div style="margin:10px 10px 30px 10px">
  <pre>{{ selectedRefs }} </pre>
</div>

I love this trick: you can see the exact contents of our "selectedRefs" array, and see it change as we tick/untick our checkboxes. This really helps when developing/testing our bindings!

Binding

As you can see, these changes use the new unique function to get your list of distinct values from your project array, and when the page first loads, we push all of the values into our new "selectedRefs" array.

["123","321","456","654","789","987"] 

Then, as you tick/untick the checkboxes, we add/remove that item from this list.

Finally, we use that filter in the ng-repeat.

ng-repeat-start="x in projects | filter:myFilter | orderBy:orderProp"

Job done !

Update

If you wanted to start off with all checkboxes unticked, then it's a simple change. Just remove this line...

ng-init="selectedRefs.push(x.b)"

..and change the myFilter function to show all items initially..

$scope.myFilter = function (item) { 
    if ($scope.selectedRefs.length == 0)
        return true;

    var idx = $scope.selectedRefs.indexOf(item.b);
    return idx != -1; 
};

And to add a "Clear all" button, simply add a button to your form which calls a function in your AngularJS controller like this..

$scope.clearAll = function () { 
    $scope.selectedRefs = [];
};

(I haven't tested these suggestions though.)

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

4 Comments

Dear lord, what css property sets a poointer to this hand?? I want to know now! :D
This is the new default cursor in Windows 10. They might choose to change it before release though. ;-)
Brilliant! Thanks a lot, really helpful for this and for future reference.
@MikeGledhill Another two questions if I dare. How would you implement a clear all button and how would you reverse the current functionality; that is to say how would you start with all checkboxes deselected with the table fully populated and then click on the checkboxes to then refine the results?
2

ng-false-value directive needs a value set. Try ng-false-value='false' or ng-false-value='null' (in fact you can skip this one entirely if it has to just be a falsy value and not something concrete, like a string or certain number).

As you've pointed out in the comments, after selecting and then clearing the checkboxes, all rows are filtered out. It happens because unchecking the checkbox will set its value to false, and this does not agree with your entities' values (as you probably know, just stating it for others).

Therefore you do need to set this value to empty string in the end. That'd be the way:

$scope.$watch('quer.$', function () {
  if ($scope.quer.$ === false) {
    $scope.quer.$ = '';
  }
});

1 Comment

This is a partial fix. Thanks for the help. The issue is that in doing this, the table data will not redisplay the columns when you deselect a checkbox and you cannot select multiple. Any ideas on this?

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.