我在angular的select指令中设置所选项目时遇到了一个问题。我不知道这是一个bug还是angular设计者有意识的设计。它确实使select指令变得不那么有用。
描述:
我的应用程序与一个REST API通信,从数据库接收一个实体。API规定,对象的关系只带ID属性发送,以便您可以在后续请求中检索它们。
的例子:
{ id : 1, customerName : "some name", city : {id : 12}}
,其中city是另一个实体,可以使用城市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的选择小部件?
就是这么简单
<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)。
剩下的只是给$scope.item
变量赋一个值,angular将通过检查项目的name
属性来确定应该将哪个元素设置为活动
它不起作用的原因是angular期望对象的引用相等。在您的情况下('select from object'在您的plnkr)创建一个新的对象,尽管具有相同的属性。然而,Angular无法知道两个不同的对象代表同一个对象。您至少有两种方法:
查找正确的城市对象实例
不将$scope.customer.city
设置为新对象,而是从$scope.cities
数组中查找实际的城市对象。如果你使用下划线,你可以这样做:
$scope.customer.city = _.find($scope.cities, function (city) {
return city.id === theCustomersCity.id;
});
绑定城市id而不是城市对象
另一种可能更容易的方法是更改ng-model
和ng-options
指令以匹配id而不是对象。
<select ng-model="customer.cityId" ng-options="i.id as i.name for i in cities"></select>
我遇到了同样的问题。我的选项和建模的数据都来自单独的API调用。
我没有通过在对象键上使用ng-model来添加间接层,而是编写了一个使用"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。city和customer_cityProxy,我得到预期的行为。
仍然有一些缺点,即只有当键不连接时才有效。
代码可在此获取:https://github.com/gosusnp/options-proxy
看看http://configit.github.io/ngyn/#select_extensions这个解决方案为我工作