AngularJS: ng model of switching int to string

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.

  1. How can I stop / bypass the behavior when my item.order is switched from INT to STRING?
  2. If this is not possible, how to make $ index be a string so that the model (string) matches the value (string)
  3. 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.

+10
javascript angularjs angular-ngmodel ng-options angularjs-ng-options
source share
3 answers

In the end, I was able to solve this by doing:

 <div class='header'> <select ng-model="item.order" ng-change="changeItemOrder((itemIndex + 1), item.order, itemIndex)"> <option ng-repeat="thing in category.items" ng-selected="(item.order === ($index + 1))" value="{{$index + 1}}">{{$index + 1}}</option> </select> </div> 

This, and only this solution (so far) has what I want / need. I need an item.order model to track the current position and show the correct value at boot time. You cannot set the model to questionIndex because it bothers other HTML elements, I cannot set it to $ index because it was also strange.

While the other solutions offered here "work", they do not lead to the specification that is given to me. Therefore, I suggest that this is characteristic.

+4
source share

It changes to a string because HTML has no idea what an integer is. Ultimately, the selected variables are read from the DOM and passed to angular, and so it changes its type.

You can make the model always contain an integer with the directive

 directive('forceInt', function() { return { require: 'ngModel', link: function(scope, element, attrs, controller) { controller.$parsers.push(function(value) { if (typeof value === 'string') { value = parseInt(value, 10); controller.$setViewValue(value); controller.$render(); } return value; }); } }; }); 

( plunk )

But I see that someone has already indicated that there may be better ways to track an order. FWIW, this directive will at least ensure that the model is never a string.

+5
source share
 .directive('numberToString', function () { return { require: 'ngModel', link: function (scope, element, attrs, ngModel) { ngModel.$parsers.push(function (value) { return '' + value; }); ngModel.$formatters.push(function (value) { return value+''; }); } } }); 
0
source share

All Articles