Установка выбранного элемента в директиве 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?
Ответы
Ответ 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
Ответ 4
Посмотрите http://configit.github.io/ngyn/#select_extensions, это решение сработало для меня
Ответ 5
http://plnkr.co/edit/Lw8uadPf4G5KYXLzeaHb показывает, что если вы установите ссылку на объект в свою область, то она будет работать.
это всего лишь немного другой третий ответ Мартинцам