0

I know various variations of this have been asked multiple times before, but nevertheless I am having trouble with it. I have a small angular app wherein I am comparing two characters (it's a D&D initiative roll). I am looking to sort the ng-repeat in the following code:

var dmTools = angular.module('dmTools', []);
dmTools.controller('initTracker', function($scope, $http) {

  var charInit = function() {
    this.name = "";
    this.mod = 0;
    this.init = 0;
  }

  $scope.characters = [

  ];

  $scope.character = new charInit();

  $scope.addChar = function() {
    $scope.characters.push($scope.character);
    $scope.character = new charInit();
  }

  $scope.deleteChar = function(character) {
    $scope.characters.splice($scope.characters.indexOf(character), 1);
  }
  $scope.charSort = function(a, b) {
    //first we go by initiative roll
    if (a.init < b.init) {
      return -1;
    }
    if (a.init > b.init) {
      return 1;
    }
    //if initiative rolls are the same, go by initiative mod
    if (a.mod < b.mod) {
      return -1;
    }
    if (a.mod > b.mod) {
      return 1;
    }
    //if both are the same, roll off until one gets a higher roll than the other.
    var aRoll = 0;
    var bRoll = 0;
    while (aRoll == bRoll) {
      aRoll = Math.floor(Math.random() * 20) + 1;
      bRoll = Math.floor(Math.random() * 20) + 1;
      if (aRoll < bRoll) {
        return -1;
      }
      if (aRoll > bRoll) {
        return 1;
      }
    }
    //while this should not be possible to reach, we'll put it in for safeties sake.
    return 0;
  };
  $scope.rollInit = function() {
    for (x in $scope.characters) {
      $scope.characters[x].init = Math.floor(Math.random() * 20) + 1 + $scope.characters[x].mod;
    }
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div class="app" id="initTracker" data-ng-controller="initTracker">
  <h3>Initiative Tracker</h3>
  <div class="form-group">
    <label>Name
      <input type="text" data-ng-model="character.name" class="form-control" />
    </label>
  </div>
  <div class="form-group">
    <label>Mod
      <input type="number" data-ng-model="character.mod" class="form-control" />
    </label>
  </div>
  <div>
    <input class="btn btn-primary" style="margin:5px;" data-ng-click="addChar()" type="button" value="Add Character" />
    <input class="btn btn-success" style="margin:5px;" data-ng-click="rollInit()" type="button" value="Roll Initiative" />
  </div>

  <table class="table table-striped">
    <tr>
      <th>Name</th>
      <th>Modifier</th>
      <th>Initiative</th>
      <th>Delete</th>
    </tr>
    <tr data-ng-repeat="character in characters | orderBy: charSort">
      <td data-ng-bind="character.name"></td>
      <td data-ng-bind="character.mod"></td>
      <td data-ng-bind="character.init"></td>
      <td>
        <input type="button" class="btn btn-danger" value="Delete" data-ng-click="deleteChar(character)" />
      </td>
    </tr>
  </table>
</div>

My charSort function is a working sort that could easily be passed to an array.sort(function) sort of call, but angular is only passing in 1 character object to the function. How can I get a proper custom comparison based sort of this variety in an angular template?

3
  • is it important to sort in this way? Commented Oct 30, 2015 at 19:32
  • The goal is to have a self-sorting table that I can use in-game for initiative order, which is ordered first by the initiative roll itself, then if there is a tie, by the modifier, and then, if that is the same as well, by a roll-off between the two tied characters. My custom sort function can accomplish this when passed to array.sort(), but angulars orderBy function doesn't function in the same way. Commented Oct 30, 2015 at 19:34
  • you can put orderBy after ng-click in this way for priorities <tr data-ng-repeat="character in characters | orderBy: ['initiative', 'modifier','rolloff'"> Commented Oct 30, 2015 at 19:43

2 Answers 2

1

Do you need to sort the array in the data-ng-repeat? You could just sort the array in rollInit().

If anything changes the array with inserts or deletes, you could $watchCollection on the array and re-sort as things are added or removed.

Then you can do any kind of sorting you like in Javascript, and the data-ng-repeat will always see the data in the correct order.

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

3 Comments

this was actually the first thing I tried, although I'm not sure where $watchCollection factors in. when I sort my array right after generating the character.init values ng-repeat doesn't seem to pick up on the change in order, even though it has no trouble recognizing that the values changed and printing the new values.
I figured out why I thought this wasn't working, and it was because my sort function was returning the wrong(reversed) order. $watchCollection isn't necessary though.
@whiplashomega I was thinking of watching the array in the controller, so that if any items are added or removed dynamically, you would see that the contents of the array have changed, and resort dynamically. But, exactly, if that is not needed, the watch is not necessary.
0

if you have three property for an object , you can sort them in priority of property A , property B and property C like below

<tr data-ng-repeat="character in characters | orderBy:['A','B','C']">

1 Comment

This would work, except that I have to sort by 'n' properties, as the rolloff continues until a > b or b > a. I could use the full random float, instead of the Math.floor(Math.random * 20) +1, which would make the chances of a tie trivially small, but then I am no longer accurately simulating the roll-off process.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.