20

angular の select ディレクティブで選択した項目を設定する際に問題があります。これがバグなのか、angular の設計者による意識的な設計なのかはわかりません。ただし、selectディレクティブの有用性が大幅に低下することは確かです。

説明:

私のアプリは REST API と通信して、データベースからエンティティを受け取ります。API は、必要に応じて後続のリクエストでそれらを取得できるように、オブジェクトの関係が ID プロパティのみで送信されることを指示します。

例:

{ id : 1, customerName : "some name", city : {id : 12}} 

ここで、都市は、都市 ID を使用して別の REST エンドポイントから取得できる別のエンティティであり、次のようになります。

{ id: 12, name : "New York"}

ユーザーがリストから適切な都市を選択できるように、可能なすべての都市を含むドロップダウン メニューを使用して顧客エンティティを編集するフォームを作成する必要があります。リストには、JSON オブジェクトから取得した顧客の市区町村が最初に表示されている必要があります。

フォームは次のようになります。

 <form>
  <input type="text" ng-model="customer.name"/>
  <select ng-model="customer.city" ng-options="i as i.name for i in cities"></select>
 </form> 

コントローラーは次のようになります。

app.controller('MainCtrl', function ($scope, $http) {
    $http.get(serviceurl + 'admin/rest/customer/' + id + "/", {
        params: {"accept": "json"},
        withCredentials: true
    }).then(function (response) {
                $scope.customer = response.data.item;
            });
    $http.get(serviceurl + 'admin/rest/city/', {
        params: {"accept": "json"},
        withCredentials: true
    }).then(function (response) {
                $scope.cities = response.data.items;
                // THIS LINE LOADS THE ACTUAL DATA FROM JSON
                $scope.customer.city = $scope.findCity($scope.customer.city);
            });
    $scope.findCity = function (city) {
        for (var i = 0; i < $scope.cities.length; i++) {
            if ($scope.cities[i].id == city.id) {
                return $scope.cities[i];
            }
        }
    }
});

何が起こるべきか: City オブジェクトの完全な詳細が読み込まれると、select ディレクティブは、リスト内の選択された項目として読み込まれた都市を設定する必要があります。

何が起こるか: リストには空のアイテムが表示され、選択されたアイテムがアイテムの配列外のオブジェクトから選択された場合、選択されたアイテムを初期化する方法がありません。

ここの問題のデモ: http://plnkr.co/edit/NavukDb34mjjnQOP4HE9?p=preview

これに対する解決策はありますか?AJAX 呼び出しと選択ロジックが再利用可能な AJAX ベースの選択ウィジェットにリファクタリングされるように、選択された項目を一般的な方法でプログラムで設定できますか?

4

4 に答える 4

42

これと同じくらい簡単です

<select
    ng-model="item"
    ng-options="item.name for item in items track by item.name">

次に、コントローラー内で:

// all items
$scope.items = [{name: 'a'}, {name: 'b'}, {name: 'c'}];
// set the active one
$scope.item = {name: 'b'};
// or just
$scope.item = $scope.items[1]

http://docs.angularjs.org/api/ng.directive:selectをチェックしてください そこから:

trackexpr : オブジェクトの配列を操作するときに使用されます。この式の結果は、配列内のオブジェクトを識別するために使用されます。trackexpr は、ほとんどの場合、value 変数 (たとえば、value.propertyName) を参照します。

残りは変数に値を代入するだけで、angular はアイテムのプロパティ$scope.itemをチェックすることで、どの要素をアクティブに設定する必要があるかを判断します。name

于 2014-01-25T19:04:51.160 に答える
21

それが機能しない理由は、angularがオブジェクト参照が等しいことを期待しているためです。あなたの場合(plnkrの'select from object')は、同じプロパティを使用していても、新しいオブジェクトを作成します。ただし、Angularは、2つの異なるオブジェクトが同じオブジェクトを表していることを認識できません。少なくとも2つのアプローチがあります。

正しい都市オブジェクトインスタンスを見つける

新しいオブジェクトに設定する代わりに、配列$scope.customer.cityから実際の都市オブジェクトを見つけます。UnderscoreJs$scope.citiesを使用している場合は、次のようなことができます。

$scope.customer.city = _.find($scope.cities, function (city) {
    return city.id === theCustomersCity.id;
});

cityオブジェクトの代わりにcityidにバインドします

もう1つのアプローチは、より簡単かもしれませんが、オブジェクトではなくidに一致するようにng-modelandディレクティブを変更することです。こちらng-optionsの実例をご覧ください。

<select ng-model="customer.cityId" ng-options="i.id as i.name for i in cities"></select>
于 2013-03-10T20:28:45.020 に答える
2

私は同じ問題に遭遇しました。私のオプションとモデル化されたデータは両方とも、別々の API 呼び出しから取得されました。

オブジェクト キーで ng-model を使用して間接レイヤーを追加する代わりに、「プロキシ」変数を使用する単純なディレクティブを作成することになりました。

<select ng-model="customer.city" ng-options="i as i.name for i in cities"></select>

になる

<select ng-model="customer_cityProxy" ng-options="i.name as i.name for i in cities"></select>

customer.city と customer_cityProxy で $watch を使用すると、期待どおりの動作が得られます。

キーが互いに素である場合にのみ機能するという点で、まだいくつかの欠点があります。

コードはこちらから入手できます: https://github.com/gosusnp/options-proxy

于 2013-08-06T12:18:14.037 に答える