我在使用关联数组绑定我的下拉列值时出现问题。
问题在于跟踪,所以当我没有将跟踪添加到我的下拉列表中时,我的下拉列表中有我的绑定,当我添加跟踪时,我无法自动选择下拉值。
我想使用带有ng-options的track by,以便角度js不会添加 $$ hashKey并利用与track by相关的性能优势。
我不明白为什么会发生这种情况。
注意:我只想为每个 $ scope.items绑定选项名称,例如披萨或汉堡,而不是整个对象
更新:据我所知,并且尝试使用我的$ scope.items的当前数据结构时,它不能使用ng-options,我想使用ng-options和track by来避免Angular js生成哈希密钥。我也按照@MarcinMalinowski的建议尝试了ng-change,但我得到了未定义的密钥。
那么$ scope.items的数据结构应该是什么,这样当我需要访问$ scope.items中的任何项目时?我可以在不进行循环的情况下访问它(就像我们从关联数组中访问项目一样),就像我现在可以使用正确的数据结构访问它并仅使用跟踪的ngoptions一样。
var app = angular.module("myApp", []);
app.controller("MyController", function($scope) {
$scope.items = [
{
"title": "1",
"myChoice" :"",
"choices": {
"pizza": {
"type": 1,
"arg": "abc",
"$$hashKey": "object:417"
},
"burger": {
"type": 1,
"arg": "pqr",
"$$hashKey": "object:418"
}
}
},
{
"title": "2",
"myChoice" :"",
"choices": {
"pizza": {
"type": 1,
"arg": "abc",
"$$hashKey": "object:417"
},
"burger": {
"type": 1,
"arg": "pqr",
"$$hashKey": "object:418"
}
}
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<ul ng-app="myApp" ng-controller="MyController">
<div ng-repeat="data in items">
<div>{{data.title}}
</div>
<select ng-model="data.myChoice"
ng-options="key as key for (key , value) in data.choices track by $index"><option value="">Select Connection</option></select>
</div>
</ul>
答案 0 :(得分:9)
您的代码中的问题是:
1)track by $index
is not supported by ngOptions
,它会导致option
的值为undefined
(在您的情况下,它将是$index
的{{1}}) ;
2)ngRepeat
不能很好地处理对象数据源(它应该与数组数据源一起使用),from the docs:
trackexpr:处理对象数组时使用。的结果 此表达式将用于标识数组中的对象。
当然,您可以使用ngRepeat
来生成track by
个元素,但就个人而言,我更倾向于使用ngOptions
而不使用option
,因为它具有track by
的优势track by
3}}
更新:以下代码说明了如何更改初始数据源并使用console.log()
预先选择一个选项,以防模型成为对象。但即使在第一个示例中,$$hashKey
也表示choices
未添加到var app = angular.module("myApp", []);
app.controller("MyController", ['$scope', '$timeout', function($scope, $timeout) {
$scope.items = [
{
"title": "1",
"myChoice" :"burger",
"choices": {
"pizza": {
"type": 1,
"arg": "abc"
},
"burger": {
"type": 1,
"arg": "pqr"
}
}
},
{
"title": "2",
"myChoice" :"",
"choices": {
"pizza": {
"type": 1,
"arg": "abc"
},
"burger": {
"type": 1,
"arg": "pqr"
}
}
}
];
$scope.itemsTransformed = angular.copy($scope.items).map(function(item){
delete item.myChoice;
item.choices = Object.keys(item.choices).map(function(choice){
item.choices[choice].name = choice;
return item.choices[choice];
});
return item;
});
//select an option like an object, not a string
$scope.itemsTransformed[1].myChoice = $scope.itemsTransformed[1].choices[0];
$timeout(function() {
//changes a prop in opts array - options are not-re-rendered in the DOM
//the same option is still selected
$scope.itemsTransformed[1].choices[0].arg = "xyz";
}, 3000);
$scope.selectionChanged =function(key, items){
console.log(items); //as we can see $$hashKey wasn't added to choices props
};
}]);
对象。
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<ul ng-app="myApp" ng-controller="MyController">
<p>Without track by:</p>
<div ng-repeat="data in items track by data.title">
<div>{{data.title}} - {{data.myChoice}}</div>
<select ng-model="data.myChoice"
ng-options="key as key for (key , value) in data.choices"
ng-change="selectionChanged(key, items)">
<option value="">Select Connection</option>
</select>
</div>
<hr/>
<p>Using track by name to pre-select an option:</p>
<div ng-repeat="data in itemsTransformed track by data.title">
<div>{{data.title}} - {{data.myChoice}}</div>
<select ng-model="data.myChoice"
ng-options="choice as choice.name for choice in data.choices track by choice.name"
ng-change="selectionChanged(key, itemsTransformed)">
<option value="">Select Connection</option>
</select>
</div>
</ul>
&#13;
$$hashKey
&#13;
更新2 :在没有ngOptions
的情况下使用track by
时,向我们显示事实var app = angular.module("myApp", []);
app.controller("MyController", ['$scope', '$timeout', function ($scope, $timeout) {
$scope.items = {
"pizza": {
"type": 1,
"arg": "abc"
},
"burger": {
"type": 1,
"arg": "pqr"
}
};
$scope.selectionChanged = function (key, items) {
console.log($scope.items);
};
}]);
属性未添加到对象的简单示例:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyController">
<hr/>
<p>Example without track by:</p>
<select ng-model="myChoice"
ng-options="key as key for (key , value) in items"
ng-change="selectionChanged(myChoice, items)">
<option value="">Select Connection</option>
</select>
<hr/>
{{myChoice}}
</div>
&#13;
$scope.itemsTransformed
&#13;
更新3:下面的最终结果(适用于angularjs版本&lt; 1.4,对于1.4+我建议在第一个代码段中将数据结构更改为angular.module("myApp", [])
.controller("MyController", ['$scope', function ($scope) {
$scope.items = [
{
"title": "1",
"myChoice": "burger",
"choices": {
"pizza": {
"type": 1,
"arg": "abc"
},
"burger": {
"type": 1,
"arg": "pqr"
}
}
},
{
"title": "2",
"myChoice": "",
"choices": {
"pizza": {
"type": 1,
"arg": "abc"
},
"burger": {
"type": 1,
"arg": "pqr"
}
}
}
];
}]);
):< / p>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyController">
<div ng-repeat="data in items track by data.title">
<div>{{data.title}} {{data.myChoice}}</div>
<select ng-model="data.myChoice"
ng-options="key as key for (key , value) in data.choices">
<option value="">Select Connection</option>
</select>
</div>
</div>
&#13;
p {
margin: 30px;
}
&#13;
答案 1 :(得分:6)
ngOptions
每个项目都没有像ngRepeat
指令那样创建新范围,因此您不需要注意摆脱$$hashKey
我会使用ng-repeat
来迭代<option>
(假设您没有创建长列表):
<select ng-model="data.myChoice">
<option value="">Select Connection</option>
<option ng-repeat="(key , value) in data.choices track by key" ng-value="key" title="{{key}}"
>{{key}}</option>
</select>
请看这个问题:github.com/angular/angular.js/issues/6564 - ng-options跟踪并选择不兼容
我认为此问题仍然存在,因此建议您使用ngRepeat
代替track by
。对于小清单,没有性能损失
答案 2 :(得分:4)
ngOptions属性可用于使用数组或对象动态生成元素的元素列表
ngModel通过引用而不是值来监视模型。将select绑定到作为对象或集合的模型时,这一点很重要。
1.如果将模型设置为与集合中的对象相等的对象,则ngOptions将无法设置选择,因为对象不相同。因此,默认情况下,您应该始终引用集合中的项目进行预选,例如:$ scope.selected = $ scope.collection [3]
例如:
$scope.items = [
{
"title": "1",
"myChoice" :"",
"choices": {
"pizza": {
"type": 1,
"arg": "abc"
},
"burger": {
"type": 1,
"arg": "pqr"
}
}
},
{
"title": "2",
"myChoice" :"",
"choices": {
"pizza": {
"type": 1,
"arg": "abc"
},
"burger": {
"type": 1,
"arg": "pqr"
}
}
}
];
从上述第2点开始,不是通过参考来追踪项目的身份。
在对象中添加key的keyName,按keyName跟踪或按arg跟踪,键入。
按arg或类型跟踪:
<select ng-model="data.myChoice"
ng-options="choice as choice.arg for choice in data.choices track by choice.arg">
<option value="">Select Connection</option>
</select>
或在选择对象中添加keyName
$scope.items = $scope.items.filter(function(item){
delete item.myChoice;
item.choices = Object.keys(item.choices).map(function(choice){
item.choices[choice].keyName = choice;
return item.choices[choice];
});
return item;
});
HTML代码:
<div ng-controller="MyCtrl">
<ul>
<div ng-repeat="data in items">
<select ng-model="data.selected"
ng-options="choice as choice.keyName for choice in data.choices track by choice.keyName"
ng-change="selection(data.selected)">
<option value="">Select</option>
</select>
</div>
</ul>
</div>
演示链接Example
答案 3 :(得分:3)
您需要添加ng-change
并在那里传递/使用您的ng-model值以获得您想要的任何属性。
答案 4 :(得分:2)
2017-09-13 12:50:45.264 WARN --- [ main] o.s.mock.web.MockServletContext : Couldn't determine real path of resource class path resource [src/main/webapp/WEB-INF/sitemesh.xml]
java.io.FileNotFoundException: class path resource [src/main/webapp/WEB-INF/sitemesh.xml] cannot be resolved to URL because it does not exist
at org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:187)
at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:49)
at org.springframework.mock.web.MockServletContext.getRealPath(MockServletContext.java:458)
at org.grails.web.sitemesh.Grails5535Factory.<init>(Grails5535Factory.java:78)
at org.grails.web.servlet.view.SitemeshLayoutViewResolver.loadSitemeshConfig(SitemeshLayoutViewResolver.java:105)
at org.grails.web.servlet.view.SitemeshLayoutViewResolver.init(SitemeshLayoutViewResolver.java:67)
at org.grails.web.servlet.view.SitemeshLayoutViewResolver.onApplicationEvent(SitemeshLayoutViewResolver.java:146)
at org.grails.web.servlet.view.SitemeshLayoutViewResolver.onApplicationEvent(SitemeshLayoutViewResolver.java:42)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:167)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:393)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:347)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:883)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at grails.boot.GrailsApp.run(GrailsApp.groovy:83)
at grails.ui.command.GrailsApplicationContextCommandRunner.run(GrailsApplicationContextCommandRunner.groovy:55)
at grails.ui.command.GrailsApplicationContextCommandRunner.main(GrailsApplicationContextCommandRunner.groovy:102)