10

我目前正在使用 Angular 开发一个应用程序。到目前为止,一切都进行得很顺利。我对 Angular 非常非常陌生,很惊讶第一个真正的障碍花了这么长时间。

情况:

我有一个对象数组,每个对象都有一个顺序。

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

用户需要能够重新排列这些项目。新订单必须设置为对象属性“订单”。

在 html 中,这些对象呈现如下:

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

在 header-div 中,我有一个输入字段,输入 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 以某种方式转换为字符串,因为在渲染时,一个选项被添加到下拉列表中,其值为“字符串:2”。

我已经以所有可能的方式尝试了 ng-options,但即使是那些也导致了问题。我做 ng-options 的方式是将 item.order 做为 item.order in ... 等等,这只是让顺序切换,直到不知何故所有项目都具有相同的顺序。尝试不同的分组方法或 trackbys 只会产生不同的错误,比如突然在下拉列表中引入 NaN en NULL,或者从 item-object 中完全删除 order 属性。

到目前为止,错误最少的解决方案是在我的选项中使用 ng-repeat。这只会导致 item.order 的类型不匹配。

现在,在广泛搜索之后,在 stackoverflow 上花费了几个小时(尤其是在用那个漂亮的小问题搜索东西写这个问题之前)我来找你。

  1. 如何停止/规避我的 item.order 从 INT 切换到 STRING 的行为?

  2. 如果那不可能,我怎么能强制我的 $index 是一个字符串,所以模型(字符串)匹配值(字符串)

  3. 如果那不可能,我该如何编写我的 ng-options 以获得我想要的行为?(我已经认真尝试了很多,从跟踪到不同的 as 和 for 语句,都导致了不同的错误)

    在初始加载时,所有选择都显示选择了正确的值,因此所有 item.order 最初都是 INT (我从我们的 API 中获取它们),只有在交互之后,除了触发重新排序的对象之外的所有内容都被搞砸了。

4

3 回答 3

5

它被更改为字符串,因为 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;
      });
    }
  };
});

笨拙

但我看到有人已经指出,可能有更好的方法来跟踪订单。FWIW 该指令至少会继续确保模型永远不是字符串。

于 2014-07-18T14:06:44.113 回答
5

最终我能够通过这样做来解决这个问题:

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

这个,只有这个解决方案(到目前为止)有我想要/需要的东西。我需要 item.order 模型来跟踪当前位置并在初始加载时显示正确的值。您不能将模型设置为 questionIndex,因为这会干扰其他 HTML 元素,我不能将其设置为 $index,因为这也会做一些奇怪的事情。

虽然此处建议的其他解决方案“有效”,但它们并没有产生给我的规范。所以我想这有点具体。

于 2014-07-18T15:56:13.407 回答
0
.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+'';
            });
        }
    }
});
于 2016-07-09T17:08:36.917 回答