3

I'm looking for a way to present a running index which ios consistent but does not run on all repeat instances.

<div class="cell" ng-repeat="c in arr">
    <div ng-if="c !== false">{{    <someIndex>   }}</div>
</div>

Assuming arr = ['word-y', false, false, 'word-x', 'word-z', false, ...], Some of the cells will have an inner value displayed, and some won't.

I'm interested in showing a running count so that the first cell will show 1, the second and third naturally empty, and the fourth will show 2, and so on (this is why $index is of no use to me).

Notes:

  1. The array on which the values are calculated must be able to change after first calculation, and values will the re-calculate.
  2. I currently do not use jQuery in this project, and if possible I would like to keep it that way.
Selfish
  • 6,023
  • 4
  • 44
  • 63
  • Your array objects change over time? those that are false may become objects? – AranS Jun 26 '16 at 08:23
  • @AranS - Yes. Those that are false might become objects, and vice-versa, some may become false after having a value. – Selfish Jun 26 '16 at 08:47
  • I'm not sure you can avoid $watching in this case. I suggest mapping your array in each change. I can give an example if you need. – AranS Jun 26 '16 at 08:50
  • Thanks, I think @Piyush.kapoor has provided enough of an example of a map. :) – Selfish Jun 26 '16 at 08:57

3 Answers3

1

Keep another array in your scope whose value would be number if the entry is not false

$scope.runningCount = [ 1, -1,-1,3,4,...]

Now inside your html use ng-repeat index to display the correct text/count

<div class="cell" ng-repeat="c in arr">
    <div ng-if="c !== false">{{   runningCount[{{index}}   }}</div>
</div>
Piyush.kapoor
  • 6,715
  • 1
  • 21
  • 21
  • This solution is legit, though not very scalable, the second array will still need to be regenerated using either a `$scope.watch()` or another event, and will require a manual loop. I'm interested in avoiding that and letting angular do the work for me. – Selfish Jun 26 '16 at 08:49
  • hmmm Angular dont have any filter to convert $index into some other index – Piyush.kapoor Jun 26 '16 at 08:55
1

UPDATE

Thne problem is you are losing the refence. You can do that with a single array. You need a array of objects.

You have a nice explanation of this issue here: Binding inputs to an array of primitives using ngRepeat => uneditable inputs

Then you can try any of the other solutions I propose to you, for example:

$scope.arr  = [{value: 'word-y'}, {value:'sd'}, {value:false}, {value:'word-x'}, {value:'word-z'}];

and:

<style type="text/css">
  .list-cell {
    counter-reset: cell;
 }
.cell_iter:before {
    counter-increment: cell;
    content: "position " counter(cell) ". ";
 }

</style>

[..]

  <ul  class="list-cell">
    <li  ng-repeat="c in arr track by $index">
      <span ng-class="{'cell_iter': c.value !== false}">{{ c.value }}</span>
    </li>
  </ul>

An example here: https://plnkr.co/edit/z0d27M8otjc16THMUPkA

OLD Reply The posible solutions:

(Solution 1)In your controller modify the array in order to have the index value:

var newArr = arr.filter(function(value){return value!== false})

(Solution 2) Or in your template:

<div class="cell" ng-repeat="c in arr | filter:filterFn">

And in yout controller:

 $scope.filterFn = function(c){ return c !== false}

(Solution 3) The solution that I most like, only css:

<div class="list-cell"> 
    <div class="cell" ng-repeat="c in arr">
        <div class="cell_iter" ng-if="c !== false">{{    <someIndex>   }}</div>
   </div>
</div>

CSS:

.list-cell {
    counter-reset: cell;
 }
.cell_iter:before {
    counter-increment: cell;
    content: "position " counter(cell) ". ";
 }

(Other solutions) You can play with ng-init in your ng-repeat. Create a new variable... But this solution will be ugly.

UPDATE ADDING NG-INIT:

the idea is to create a new property in the parent context to ng-repeat and inside the ng-repeat another different context.

We will do all this in the template (Ugly):

  <ul class="example-animate-container"  ng-init="$counterHelper=0">
    <li class="animate-repeat" ng-repeat="c in arr track by $index" ng-init="$parent.$counterHelper = c !== false?$counterHelper +1:$counterHelper; p={}; p.value=c; p.$counter = $counterHelper;">
      [{{$index + 1}}] [{{ p.$counter }}] {{ p.value }} 
    </li>
  </ul>

here an example: https://plnkr.co/edit/z0d27M8otjc16THMUPkA?p=preview

Community
  • 1
  • 1
Raúl Martín
  • 4,471
  • 3
  • 23
  • 42
  • Thanks for the answer! 1,2 aren't relevant, as I don't want to filter out the empty divs, I gave a simplified example, but the use case is more complex, and they do contain other elements. I will try No. 3. – Selfish Jun 26 '16 at 10:21
  • Okay, that doesn't cover my use case as well. Would you mind sharing the `ng-init` option as well? – Selfish Jun 26 '16 at 10:25
  • @CommonRaven I update the reply with ng-init. I think is an interesting thing to show. – Raúl Martín Jun 26 '16 at 10:51
  • Thank you so much for your efforts, very disappointed to say ng-init won't do the trick for an update of the data (question note 1). I have forked your plunker and added a setTimeout in the controller which changes the data. https://plnkr.co/edit/DrqmcuhJ8dxa4IjcU9OI – Selfish Jun 26 '16 at 11:03
  • @CommonRaven With the example is easy to understand the problem. I update the reply – Raúl Martín Jun 26 '16 at 11:46
  • any luck? @CommonRaven – Raúl Martín Jun 28 '16 at 10:27
  • Nope, currently, as an intermediate solution I'm mapping my array to another and using the second one for the running index, but I'm not pleased with the solution. – Selfish Jun 28 '16 at 10:29
0

I believe there is a simple and elegant solution by just using an angular filter to "filter out" the falsey elements in the array, for example, try this:

<div class="cell" ng-repeat="c in $ctrl.arr | filter: '!false' track by $index">
    <div>{{ c }} {{ $index }}</div>
</div>

(note you don't actually need the ng-if anymore!)

Cheers!

danii
  • 5,553
  • 2
  • 21
  • 23
  • Thanks for the answer, this does not work with my use case, as I don't want to filter out the empty divs, I gave a simplified example, but the use case is more complex, and they do contain other elements.. – Selfish Jun 26 '16 at 10:20