跟踪下拉绑定问题

Lea*_*sed 16 javascript angularjs

我在使用关联数组绑定我的下拉列值时遇到问题.

问题是跟踪,因为当我没有添加跟踪到我的下拉列表然后我有我的下拉列表和当我添加跟踪时,我无法自动选择下拉值.

我想使用带有ng-options的track by,以便angular js不会添加$$ hashKey并利用与track by相关的性能优势.

我不明白为什么会发生这种情况.

注意:我只想为每个$ scope.items而不是整个对象绑定像Pizza或burger这样的选项名称.

更新:据我所知,并且尝试使用我的$ scope.items的当前数据结构,它不能使用ng-options,我想使用跟踪的ng-options来避免Angular js生成散列键.我也按照@MarcinMalinowski的建议尝试了ng-change,但是我得到了未定义的密钥.

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

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"
        }
      }
   }
  ];
   
});
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

Sta*_*ash 9

代码中的问题是:

1)track by $index不被支持的ngOptions,它将导致的值optionundefined(在你的情况下这将是一个$indexngRepeat);

2)从文档中track by对象数据源(它应该与数组数据源一起使用)不能很好地工作:

trackexpr:在处理对象数组时使用.此表达式的结果将用于标识数组中的对象.

当然,你可以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
  };
   
}]);
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

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

}]);
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

更新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"
                }
            }
        }
    ];
}]);
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)


Max*_*tin 6

ngOptions不会为ngRepeat每个项目创建新的范围,因此您不需要注意摆脱$$hashKey

我会ng-repeat用来迭代<option>(假设你不创建长列表):

<select ng-model="data.myChoice">    
    <option value="">Select Connection</option>
    <option ng-repeat="(key , value) in data.choices track by key" ng-value="key" title="{{key}}"
    >{{key}}</option>
</select>
Run Code Online (Sandbox Code Playgroud)

Working Demo Fiddle


看看这个问题:github.com/angular/angular.js/issues/6564 - ng-options跟踪并选择不兼容

我相信这个问题仍然存在,因此建议您使用ngRepeattrack by替代.对于小型列表,没有性能损失