2017-09-07 86 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

    非常感謝您爲幫助而付出的努力,請繼續提供幫助。讚賞:) –