web-dev-qa-db-ja.com

ng-optionsの選択した値を設定できません

ドロップダウン選択オプションリストを作成し、ng-modelおよびng-optionsを使用してデフォルトの選択値を設定しようとしています。

私のビューには次のコードがあります:

<select ng-model="thisTour.site" ng-options="site.name for site in siteList"></select>

そして、私のコントローラーで:

    $scope.siteList = [
        { id: 1, name: 'cycling'},
        { id: 2, name: 'walking'},
        { id: 3, name: 'holidays'}
    ]

    $scope.thisTour.site = { id: 2, name: 'walking'};

リストにはsiteListオブジェクトから正しい3つのオプションが入力されていますが、デフォルトではwalkingを選択していません。何故なの?

さて、これを変更すると:

$scope.thisTour.site = { id: 2, name: 'walking'};

これに:

$scope.thisTour.site = $scope.siteList[1];

今では動作します。どうして?同じことではないですか?

15
Inigo

これは、angularはオブジェクトの等価性を探して構文にバインドし、あなたの場合は$scope.siteList[1]{ id: 2, name: 'walking'};と等しくないためです(2つのオブジェクトは、これはさまざまな方法で回避できます。1つの簡単な方法は、track by構文とng-optionsを使用してidでトラックを指定することです。これにより、ng-optionのオプションがオブジェクト参照自体ではなく、バインドされたオブジェクトの指定されたプロパティによって追跡されます。

<select ng-model="thisTour.site" 
    ng-options="site.name for site in siteList track by site.id"></select>

また、構文を使用してng-modelを最小限に設定し、構文のselect as部分を使用してidのみを指定することもできます:

例:-

ng-options="site.id as site.name for site in siteList"

そして、モデルは次のようになります:-

 $scope.thisTour.site = 2;
angular.module('app', []).controller('ctrl', function($scope){
  $scope.thisTour = {};
 $scope.siteList = [
        { id: 1, name: 'cycling'},
        { id: 2, name: 'walking'},
        { id: 3, name: 'holidays'}
    ]

    $scope.thisTour.site = { id: 2, name: 'walking'};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
  <select ng-model="thisTour.site" ng-options="site.name for site in siteList track by site.id"></select>
  {{thisTour.site}}
  </div>

ドキュメント から

trackexpr:-オブジェクトの配列を操作するときに使用されます。この式の結果は、配列内のオブジェクトを識別するために使用されます。 trackexprはほとんどの場合、値変数を参照します(例:value.propertyName)。これにより、オプションが再作成された場合(たとえば、サーバーから再ロードされた場合)でも、選択は保持されます。

また、注目に値する:

同じ式でselect asおよびtrack byを使用しないでください。彼らは一緒に動作するように設計されていません。

46
PSL

Javascriptのオブジェクトは参照渡しであるため、これは同じことではありません。

最初の例を取り上げると:

$scope.siteList = [
    { id: 1, name: 'cycling'},
    { id: 2, name: 'walking'},
    { id: 3, name: 'holidays'}
]

$scope.thisTour.site = { id: 2, name: 'walking'};

次に、これを行います:

$scope.thisTour.site.id = 3;
console.log($scope.siteList[1].id) // 2

言い換えると、2つのオブジェクトはvalueで等しいものの、同じオブジェクトではありません。 ngOptionsディレクティブはこれを見るため、thisTour.siteは許可されたオプションの1つではないため、空白の値になります。

Googleが「javascriptの参照渡し」をご覧ください。

3
Ed Hinchliffe

Selectでオブジェクト全体を使用しているので、Angularが比較を行うとき、selectを設定するためにオブジェクトが同じであるかどうかを確認します。 Angularは比較を行う方法で機能を変更しますが、選択をループして、以下のような独自の比較を行うだけです。

$scope.siteList = [
        { id: 1, name: 'cycling'},
        { id: 2, name: 'walking'},
        { id: 3, name: 'holidays'}
    ]
angular.forEach($scope.siteList, function(site, index) {
    if (site.id == 2) {
        $scope.thisTour.site = site;
    }
});

これにより、実際のオブジェクトが変数に設定され、selectで設定できるようになります。

1
Matthew Green

Ng-initディレクティブに使用します。ngmodelに値を割り当てることができるときに最初に実行されます。

<div ng-init="thisTour.site = siteList[position]">
    <select ng-model="thisTour.site" ng-options="site.name for site in  siteList track by site.id"></select>
</div>
0
Arul Ramalingam