Подтвердить что ты не робот

Установка выбранного элемента в директиве select

У меня возникла проблема с установкой выбранного элемента в директиве angular select. Я не знаю, является ли это ошибкой или сознательным дизайном дизайнеров angular. Это, безусловно, делает директиву select намного менее полезной, хотя.

Описание:

Мое приложение связывается с REST API для получения сущности из базы данных. API диктует, что отношения объекта отправляются с идентификационным свойством только для того, чтобы вы могли получить их в последующих запросах, если это необходимо.

Пример:

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

где город - это другой объект, который может быть получен через другую конечную точку REST с использованием идентификатора города и выглядит так:

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

Мне нужно создать форму для редактирования объекта клиента с выпадающим меню со всеми возможными городами, чтобы пользователь мог выбрать город-appopriate из списка. Список должен первоначально отображать город клиента, полученный из объекта 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 должна установить город, который был загружен как выбранный элемент в списке.

Что происходит: в списке отображается пустой элемент, и нет возможности инициализировать выбранный элемент, если выбранный элемент из объектов вне массива элементов.

DEMO проблемы здесь: http://plnkr.co/edit/NavukDb34mjjnQOP4HE9?p=preview

Есть ли для этого решения? Может ли выбранный элемент быть установлен программным способом общим образом, чтобы логические вызовы и выбор логики AJAX были реорганизованы в многократно используемый виджет выбора на основе AJAX?

4b9b3361

Ответ 1

Это так просто, как это

<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.propertyName).

Остальное просто присваивает значение переменной $scope.item, а angular будет определять, какой элемент должен быть установлен как активный, проверяя свойство item name.

Ответ 2

Причина, по которой он не работает, заключается в том, что angular ожидает, что ссылки на объекты будут равны. В вашем случае ( "select from object" в вашем plnkr) создает новый объект, хотя и с теми же свойствами. Однако angular не может знать, что два разных объекта представляют один и тот же объект. У вас есть как минимум два подхода:

Найти правильный экземпляр объекта города

Вместо того, чтобы устанавливать $scope.customer.city на новый объект, найдите фактический объект города из массива $scope.cities. Если вы используете UnderscoreJs, вы можете сделать что-то вроде:

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

Привязать к идентификатору города вместо объекта города

Другим подходом, который может быть проще, является изменение директив ng-model и ng-options для соответствия идентификатору вместо объекта. См. Рабочий пример здесь.

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

Ответ 3

Я столкнулся с той же проблемой. Мои параметры и смоделированные данные поступали из отдельных вызовов API.

Вместо добавления слоя косвенности с использованием ng-модели на объектных ключах я закончил тем, что написал простую директиву, в которой используется переменная "proxy".

<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>

Используя $watch на customer.city и customer_cityProxy, я получаю ожидаемое поведение.

Есть еще несколько недостатков, поскольку он работает только в том случае, если ключи не пересекаются.

Код доступен здесь: https://github.com/gosusnp/options-proxy

Ответ 5

http://plnkr.co/edit/Lw8uadPf4G5KYXLzeaHb показывает, что если вы установите ссылку на объект в свою область, то она будет работать. это всего лишь немного другой третий ответ Мартинцам