javascript - track by 的下拉绑定(bind)问题

标签 javascript angularjs

我在将下拉值与关联数组绑定(bind)时遇到问题。

问题出在 track by 上,例如当我不将 track by 添加到我的下拉菜单时,我与下拉列表绑定(bind),当我添加 track by 时,O 无法自动选择下拉列表值。

我想将 track by 与 ng-options 一起使用,这样 angular js 就不会添加 $$hashKey 并利用与 track by 相关的性能优势。

我不明白为什么会发生这种行为。

注意:我只想为我的每个 $scope.items 而不是整个对象绑定(bind)选择名称,例如披萨或汉堡 .

更新:据我所知,我对 $scope.items 的当前数据结构进行了很多尝试,它不适用于 ng-options,我想使用 ng-options 和 track by to避免通过 Angular js 生成哈希键。我也按照@MarcinMalinowski 的建议尝试了 ng-change,但我得到的 key 是未定义的。

那么我的 $scope.items 的数据结构应该是什么,以便当我需要从我的 $scope.items 访问任何项目时?我可以在不执行循环的情况下访问它(就像我们从关联数组访问项目一样),就像我现在如何使用正确的数据结构访问它并仅使用 ngoptions 和 track by。

var app = angular.module("myApp", []);
app.controller("MyController", function($scope) {
  $scope.items = [
  {
    "title": "1",
    "myChoice" :"",
      "choices": {
        "pizza": {
          "type": 1,
          "arg": "abc",
          "$$hashKey": "object:417"
        },
        "burger": {
          "type": 1,
          "arg": "pqr",
          "$$hashKey": "object:418"
        }
      }
   },
   {
    "title": "2",
     "myChoice" :"",
      "choices": {
        "pizza": {
          "type": 1,
          "arg": "abc",
          "$$hashKey": "object:417"
        },
        "burger": {
          "type": 1,
          "arg": "pqr",
          "$$hashKey": "object:418"
        }
      }
   }
  ];
   
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<ul ng-app="myApp" ng-controller="MyController">
   <div ng-repeat="data in items">
       <div>{{data.title}}
       </div>
     <select ng-model="data.myChoice" 
     ng-options="key as key for (key , value) in data.choices track by $index"><option value="">Select Connection</option></select>
   </div>
   
   </ul>

最佳答案

您的代码中存在的问题是:

1) track by $index is not supported by ngOptions , 它将产生 option 的值成为undefined (在您的情况下,它将是 $indexngRepeat );

2) track by不适用于对象数据源(它应该与数组数据源一起使用),from the docs :

trackexpr: Used when working with an array of objects. The result of this expression will be used to identify the objects in the array.

当然可以用 ngRepeat 生成 option元素,但就个人而言,我更喜欢使用 ngOptions 没有track by由于它有超过 ngRepeat 的好处.

更新:这里的代码说明了如何更改初始数据源并使用 track by在模型是对象的情况下预先选择一个选项。但即使在第一个例子中 console.log()表明$$hashKey未添加到 choices对象。

var app = angular.module("myApp", []);
app.controller("MyController", ['$scope', '$timeout', function($scope, $timeout) {
  $scope.items = [
  {
    "title": "1",
    "myChoice" :"burger",
      "choices": {
        "pizza": {
          "type": 1,
          "arg": "abc"
        },
        "burger": {
          "type": 1,
          "arg": "pqr"
        }
      }
   },
   {
    "title": "2",
     "myChoice" :"",
      "choices": {
        "pizza": {
          "type": 1,
          "arg": "abc"
        },
        "burger": {
          "type": 1,
          "arg": "pqr"
        }
      }
   }
  ];
  
  $scope.itemsTransformed = angular.copy($scope.items).map(function(item){
    delete item.myChoice;
    item.choices = Object.keys(item.choices).map(function(choice){
        item.choices[choice].name = choice;
        return item.choices[choice];
    });
    return item;
  });
  
  //select an option like an object, not a string
  $scope.itemsTransformed[1].myChoice = $scope.itemsTransformed[1].choices[0];
  
  $timeout(function() {
    //changes a prop in opts array - options are not-re-rendered in the DOM
    //the same option is still selected
    $scope.itemsTransformed[1].choices[0].arg = "xyz";
  }, 3000);
  
  $scope.selectionChanged =function(key, items){
    console.log(items); //as we can see $$hashKey wasn't added to choices props
  };
   
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<ul ng-app="myApp" ng-controller="MyController">
   <p>Without track by:</p>
   <div ng-repeat="data in items track by data.title">
     <div>{{data.title}} - {{data.myChoice}}</div>
       
     <select ng-model="data.myChoice" 
             ng-options="key as key for (key , value) in data.choices"
             ng-change="selectionChanged(key, items)">
       <option value="">Select Connection</option>
     </select>
     
   </div>
   <hr/>
    <p>Using track by name to pre-select an option:</p>
    <div ng-repeat="data in itemsTransformed track by data.title">
     <div>{{data.title}} - {{data.myChoice}}</div>
       
     <select ng-model="data.myChoice" 
             ng-options="choice as choice.name for choice in data.choices track by choice.name"
             ng-change="selectionChanged(key, itemsTransformed)">
       <option value="">Select Connection</option>
     </select>
     
   </div>
</ul>

更新 2:一个向我们展示事实的简单示例 $$hashKey使用 ngOptions 时未将属性添加到对象没有track by :

var app = angular.module("myApp", []);
app.controller("MyController", ['$scope', '$timeout', function ($scope, $timeout) {
    $scope.items = {
        "pizza": {
          "type": 1,
          "arg": "abc"
        },
        "burger": {
          "type": 1,
          "arg": "pqr"
        }
      };

    $scope.selectionChanged = function (key, items) {
        console.log($scope.items);
    };

}]);
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyController">
    <hr/>
    <p>Example without track by:</p>

    <select ng-model="myChoice"
            ng-options="key as key for (key , value) in items"
            ng-change="selectionChanged(myChoice, items)">
        <option value="">Select Connection</option>
    </select> 
    <hr/>
    {{myChoice}}
</div>

更新 3: 下面的最终结果(适用于 angularjs 版本 < 1.4,对于 1.4+ 我建议在第一个代码片段中将数据结构更改为 $scope.itemsTransformed):

angular.module("myApp", [])
.controller("MyController", ['$scope', function ($scope) {
    $scope.items = [
        {
            "title": "1",
            "myChoice": "burger",
            "choices": {
                "pizza": {
                    "type": 1,
                    "arg": "abc"
                },
                "burger": {
                    "type": 1,
                    "arg": "pqr"
                }
            }
        },
        {
            "title": "2",
            "myChoice": "",
            "choices": {
                "pizza": {
                    "type": 1,
                    "arg": "abc"
                },
                "burger": {
                    "type": 1,
                    "arg": "pqr"
                }
            }
        }
    ];
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyController">
    <div ng-repeat="data in items track by data.title">
        <div>{{data.title}} {{data.myChoice}}</div>

        <select ng-model="data.myChoice"
                ng-options="key as key for (key , value) in data.choices">
            <option value="">Select Connection</option>
        </select>

    </div>
</div>

关于javascript - track by 的下拉绑定(bind)问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46100223/

相关文章:

javascript - 无法加载资源错误 : the server responded with a status of 404(not found)

javascript - 检索要在标题文本中使用的 anchor 文本

angularjs - 让 ng-repeat 使用对象属性顺序

javascript - 使用过滤器对 AngularJS 中的元素进行分组

android - 文本段落程序逻辑中的用户标记

AngularJS:如果元素具有ngModel和具有本地范围的指令,则两种方式数据绑定(bind)失败

javascript - 在事件监听器内的匿名函数内运行函数

javascript - 我正在尝试使用 2captcha api 绕过 funcaptcha

javascript - && 逻辑运算符的这两种用法有什么区别?

javascript - Gulp 在 uglify() 未处理的错误事件上失败