I am currently working on an application on Angular. So far, everything is going well. I am really, really new to angular and amazed that it took so long for the first real roadblock.
Situation:
I have an array of objects, each of which has an order.
category.items = [{id: 1, order: 1, type: {}, ...}, {id: 54, order: 2, type: {}, ...}, {id: 3, order: 3, type: {}, ...}]
The user should be able to rearrange these elements. The new order must be set to the 'order' property of the object.
In HTML, these objects are displayed like this:
<div class="category"> <div class="item" ng-repeat="(itemIndex, item) in category.items track by $index"> <div class="header"> </div> </div> </div>
In the header-div, I have an input field, type select.
<select ng-model="item.order" ng-change="changeItemOrder((itemIndex + 1), item.order, itemIndex)"> <option ng-repeat="item in category.items" ng-value="($index + 1)">{{$index + 1}}</option> </select>
Code for changeItemOrder:
$scope.changeItemOrder = function(old_order, new_order, item_index) { new_order = parseInt(new_order); if (old_order != new_order) { var upper = Math.max(old_order, new_order); var lower = Math.min(old_order, new_order); angular.forEach($scope.category.items, function(item, key) { if (item_index != key) { if (new_order < old_order) { if (item_index >= new_order && (key + 1) >= lower && (key + 1) <= upper) { item.order = (parseInt(item.order) + 1); } } else if (new_order > old_order) { if (item_index <= old_order && (key + 1) <= upper && (key + 1) >= lower) { item.order = (parseInt(item.order) - 1); } } } else { item.order = parseInt(new_order); } }); $scope.reorderItems(); } };
(ReorderItems simply calls angular sorting with a default sorting mechanism that compares orders and returns -1, 1, or 0.)
This is where I discovered / noticed / identified one of the most serious errors in one of the possible solutions to this problem. Here I noticed that my INT is somehow converted to a string, because when rendering, an option with the value 'string: 2' is added to the drop-down list.
I tried ng-options in every possible way, but even they led to problems. I did ng-options using item.order as item.order in ... and so on, which just made the order switch until all the elements had the same order. An attempt to use different grouping methods or trackbys led to various errors, for example, the sudden introduction of NaN en NULL in the drop-down list or the complete removal of the order property as a whole from the object object.
So far, the least error prone solution was to use ng-repeat in my options. This only leads to a mismatch of type item.order.
Now, after a long search, having spent hours on upflow (especially before writing this question with the help of this elegant little thing in searching for questions), I came to you.
- How can I stop / bypass the behavior when my item.order is switched from INT to STRING?
- If this is not possible, how to make $ index be a string so that the model (string) matches the value (string)
If this is not possible, how can I write my ng parameters to get the desired behavior? (I seriously tried a lot, from tracking to various, as for statements, all led to various errors)
At the initial loading, all selectors show the correct selected value, therefore all item.order is originally INT (I get them from our API), only after the interaction everything except the object that caused the reordering got corrupted.