javascriptangularjsangularjs-ng-repeatangular-ui-tree

How to add items to nested angular-ui-tree list after reorder?


I have a nested list of items, something like Day > Exercises > Sets.
Each day can have many exercises and each exercise can have many sets.
For each list there is a add button.

Everything works great until you reorder them using angular-ui-tree.

If you swap the first exercise with the second one and then click on the + set button, the new set position it's not the correct one.

Here's the codepen.
Try swapping 2 exercises of the same day and then click on the + set that belongs to eighter one of the exercises.

I know that the problem is caused by the variables set in ng-init directive but I can't find any solution.

Thank you.

<ul ng-model="program.days" ui-tree-nodes>
  <li ng-repeat="day in program.days" ng-init="dayIndex = $index" ui-tree-node>
    <div class="day">{{ day.name }}</div>

    <!-- Exercises -->
    <ul ng-model="day.exercises" ui-tree-nodes>
      <li ng-repeat="ex in day.exercises" ng-init="exIndex = $index" ui-tree-node>
        <div>{{ ex.name }}</div>

        <!-- Sets -->
        <ul ng-model="ex.sets" ui-tree-nodes>
          <li ng-repeat="set in ex.sets" ui-tree-node>
            <div>{{ set.reps }} reps</div>
          </li>
          <li><button ng-click="addSet(dayIndex, exIndex)">+ set</button></li>
        </ul>
        <!-- end Sets -->

      </li>
      <li><button ng-click="addExercise(dayIndex)">+ exercise</button></li>
    </ul>
    <!-- end Exercises -->

  </li>
  <li><button ng-click="addDay()">+ day</button></li>
</ul>
<!-- end Days -->

Solution

  • Ng-init is not good to what you is doing. When work with nested arrays, try to pass the object, not the index, will keep your code clean.

    This is the example:

    <ul>
        <li ng-repeat="day in program.days">
            <div class="day">{{ day.name }}</div>
            <ul>
                <li ng-repeat="ex in day.exercises">
                    <div class="ex">{{ ex.name }}</div>
                </li>
            </ul>
        </li>
        <li><button ng-click="addExercice(day)">+ set</button></li>
    </ul>
    

    With that you passing your "day" object to your function, so any change in this object will reflect your html:

    $scope.addExercice = function(day) {
        day.exercices.push({});
    };