AngularJS: ng-модель переключения int в строку

в настоящее время я работаю над приложением в Angular. До сих пор все шло хорошо. Я действительно, действительно новый угловой и удивлен, что это заняло так много времени для первого реального блокпоста.

ситуация:

у меня есть массив объектов, каждый с заказом.

category.items = [{id: 1, order: 1, type: {}, ...}, {id: 54, order: 2, type: {}, ...}, {id: 3, order: 3, type: {}, ...}]

пользователь должен иметь возможность переставлять эти элементы. Новый порядок должен быть установлен в свойство object 'order'.

в html эти объекты вот так:

<div class="category">
    <div class="item" ng-repeat="(itemIndex, item) in category.items track by $index">
        <div class="header">
        </div>
    </div>
</div>

в заголовке-div у меня есть inputfield, введите 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>

код для 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 просто вызывает угловую сортировку с механизмом сортировки по умолчанию, сравнивая заказы и возвращая -1, 1 или 0.)

вот где я обнаружил / заметил / определил одну из ошибок взлома в одном из возможных решений этой проблемы. Здесь я заметил, что мой INT преобразуется для строки как-то, как при рендеринге, в раскрывающийся список добавляется опция со значением 'string:2'.

Я пробовал ng-options всеми возможными способами, но даже они привели к проблемам. То, как я сделал ng-options, - это сделать элемент.заказать товар.порядок ... и так далее, это просто заставило заказ переключаться, пока каким-то образом все предметы не имели тот же порядок. Попытка различных методов группировки или trackbys просто дала разные ошибки, такие как внезапное введение NaN en NULL в раскрывающемся списке или полное удаление свойство order в целом из item-object.

до сих пор наименее ошибочным решением было использование ng-repeat на моих опциях. Это только вызывает несоответствие типа элемента.порядок.

теперь, после поиска повсюду, тратя часы на stackoverflow (особенно перед написанием этого вопроса с этим изящным маленьким вопросом-поиском), я прихожу к вам.

  1. как я могу остановить / обойти поведение, в котором мой элемент.заказ переключен от INT до STRING?
  2. если это невозможно, как я могу заставить мой $ index быть строкой, поэтому модель(строка) соответствует значению (строке)
  3. если это невозможно, как я могу написать свои ng-options, чтобы получить поведение, которое я хочу? (Я серьезно пробовал много, от track by до разных AS и для заявлений, все привело к различным ошибкам)

    при начальной загрузке все выбранные значения показывают правильное выбранное значение, поэтому все элементы.порядок изначально INT (я получаю они из нашего API), только после взаимодействия все, кроме объекта, который вызвал переупорядочение, испортились.

3 ответов


он изменяется на строку, потому что HTML не имеет понятия о том, что такое целое число. В конечном счете выбранные переменные считываются из DOM и передаются в angular, и поэтому он меняет свой тип.

вы можете заставить модель всегда содержит целое число с директивой

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;
      });
    }
  };
});

(цок)

но я вижу, что кто-то уже указал, что могут быть лучшие способы отслеживать порядок. Чистки рядов эта директива будет, по крайней мере, делать конечно, модель никогда не является строкой.


в конце концов, я смог решить это сделать:

<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>

это, и только это решение (до сих пор) имеет то, что я хочу/нужно. Мне нужен предмет.модель заказа для отслеживания текущей позиции и отображения правильного значения при начальной нагрузке. Вы не можете установить модель в questionIndex, потому что это нарушает другие HTML-элементы, я не могу установить ее в $index, потому что это также сделало странные вещи.

в то время как другие решения, предложенные здесь "работают", Они не приводят в спецификации это было дано мне. Так что, думаю, это довольно специфично.


.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+'';
            });
        }
    }
});