2017-09-07 54 views
16

我在绑定与关联数组的下拉值时出现问题。与轨道的下拉绑定问题

问题是跟踪如此喜欢,当我不添加跟踪到我的下拉列表,然后我有我的绑定与下拉列表,当我添加轨道,然后O无法自动选择下拉值。

我想用ng-options跟踪,这样角度js不会添加 $$ hashKey并利用与track by相关的性能优势。

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

注:我只是想绑定的选择比萨或汉堡我的每$ scope.items,而不是整个对象

更新:据我所知,与我的$ scope.items的当前数据结构的这么多尝试它不是与ng-options一起工作,我想用ng-options跟踪来避免生成散列键由Angular js。我也尝试了@MarcinMalinowski建议的ng-change,但是我得到的关键是未定义的。

那么,我的数据结构$ 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>

+0

为什么不'轨道由$ index' –

+3

@MaximShoustin添加trackby $索引总是最后autoselecting item.See我的更新我添加了$指数,现在我无法选择任何其他项目 –

+0

当提及自己(“我”)时,请始终使用大写字母。这样可以节省一些志愿编辑在改进你的帖子时的工作(大概所有278人都有相同的错误)。谢谢! – halfer

回答

9

在你的代码的问题是:

1)track by $index is not supported by ngOptions,这将导致该option的价值是undefined(在你的情况这将是ngRepeat$index) ;与对象的数组工作时使用:

2)track by不能很好与对象数据源的工作(它应该与阵列数据源一起使用),from the docs

trackexpr。 的结果将用于识别数组中的对象。

当然,你可以用ngRepeat产生option元素,但就个人而言,我宁愿不使用track by由于ngOptions它拥有ngRepeat的好处。

UPDATE:这里是代码,演示如何改变你的初始数据源,并使用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>

UPDATE 3:

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>

:下面(与angularjs版本< 1.4工作,为1.4+我建议改变所述数据结构$scope.itemsTransformed在第一代码片段)
最终结果
+0

Upvoted为你的善待努力帮助我,但没有跟踪的ng选项有ng-repeat的性能优势? –

+0

ng-options没有轨道的问题会产生散列,通过它我在我的问题中说过,我不想要那样。这就是为什么我想要使用轨道,以便角度不会通过跟踪更改生成散列 –

+0

@Learning,尝试删除轨道by'from ngOptions',我没有看到'$$ hashKey'被创建(将添加代码来说明)。用'ngRepeat'跟踪''在性能方面是有意义的,但我不确定它在'ngOptions'指令中扮演着同样的角色 - 就像它用于在重新创建选项时保留选择的文档一样。 –

3

您需要添加ng-change和通过/用你的NG-模型值那里得到任何你想要的属性。

+1

Upvoted为您的善意努力,帮助我,但我有点困惑在这里。如果我在那里设置我的ng模型的价值,那么选择什么应该是我的ng模型。您能否请添加您所说的任何样本代码? –

+0

'ng-change =“youFuncHere(key)”' –

+0

但是当我不在我的下拉列表中添加ng-model时,我得到一个错误:无法找到指令'ngOptions'所需的控制器'ngModel'!你是说我指定了ng-model,但仍然在你的functionFHere方法中设置了我的模型? –

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> 

Working Demo Fiddle


拿来看这个问题:github.com/angular/angular.js/issues/6564 - NG选项跟踪通过并选择以不兼容

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

+0

Upvoted为你的善良努力来帮助我,但你能解释我一点关于这个,像我的代码中的问题是什么,为什么不ng-options? –

+1

@学习代码没有问题,但结构复杂。所以我用'ng-repeat'代替了'ngOptions'指令# –

+0

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

4

ngOptions属性可用于动态生成使用数组或对象的元素列表

ngModel监视模型b y引用,而不是值。这对于将选择绑定到作为对象或集合的模型时很重要。

1.如果将模型设置为与您的集合中的对象相等的对象,则由于对象不相同,因此ngOptions将无法设置选择。所以在默认情况下,你应该总是你的收集预选,在引用该项目如:$ scope.selected = $ scope.collection [3]

  • ngOptions将跟踪的身份项目不是通过引用,而是通过表达式进行追踪的结果。例如,如果您的收藏品具有ID属性,则可以按item.id进行跟踪。
  • 例如:

    $scope.items = [ 
        { 
        "title": "1", 
        "myChoice" :"", 
         "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" 
         } 
         } 
        } 
        ]; 
    

    从上述第二点,通过参考跟踪物品的身份不。

    在对象中添加键名的keyName,并通过keyName或track按arg键入类型。

    轨道由ARG或类型:

    <select ng-model="data.myChoice" 
           ng-options="choice as choice.arg for choice in data.choices track by choice.arg"> 
          <option value="">Select Connection</option> 
         </select> 
    

    或者添加的keyName选择对象内部

    $scope.items = $scope.items.filter(function(item){ 
        delete item.myChoice; 
        item.choices = Object.keys(item.choices).map(function(choice){ 
         item.choices[choice].keyName = choice; 
         return item.choices[choice]; 
        }); 
        return item; 
        }); 
    

    HTML代码:

    <div ng-controller="MyCtrl"> 
        <ul> 
        <div ng-repeat="data in items"> 
        <select ng-model="data.selected" 
          ng-options="choice as choice.keyName for choice in data.choices track by choice.keyName" 
          ng-change="selection(data.selected)"> 
         <option value="">Select</option> 
        </select> 
    
        </div> 
        </ul> 
    </div> 
    

    演示链接Example

    +0

    非常感谢您的帮助,并请继续提供帮助。请谅解:) –

    2
    <select class="form-control pickupaddress ng-pristine ng-valid ng-touched m-r-sm m-t-n-xs" ng-model="item.pickup_address" tabindex="0" aria-invalid="false" ng-options="add._id as add.nick_name for add in addPerFood[item.food._id] | unique:'nick_name'" ng-change="dropDownSelect(item.pickup_address,allCarts,item,$index)"> 
    
    +0

    请尝试解释更多。 –

    +0

    非常感谢您为帮助而付出的努力,请继续提供帮助。赞赏:) –