use*_*038 15 javascript refresh angularjs ng-options
我有一个组合框,基本上select是一个由复杂对象数组填充的元素ng-options.当我在二级更新集合的任何对象时,此更改不会应用于组合框.
这也记录在AngularJS网站上:
请注意,
$watchCollection对象的属性(如果模型是数组,则为集合中的项)进行浅层比较.这意味着更改比对象/集合内的第一级更深的属性不会触发重新呈现.
<div ng-app="testApp">
<div ng-controller="Ctrl">
<select ng-model="selectedOption"
ng-options="(selectedOption.id + ' - ' + selectedOption.name) for selectedOption in myCollection track by selectedOption.id">
</select>
<button ng-click="changeFirstLevel()">Change first level</button>
<button ng-click="changeSecondLevel()">Change second level</button>
<p>Collection: {{ myCollection }}</p>
<p>Selected: {{ selectedOption }}</p>
</div>
</div>
Run Code Online (Sandbox Code Playgroud)
var testApp = angular.module('testApp', []);
testApp.controller('Ctrl', ['$scope', function ($scope) {
$scope.myCollection = [
{
id: '1',
name: 'name1',
nested: {
value: 'nested1'
}
}
];
$scope.changeFirstLevel = function() {
var newElem = {
id: '1',
name: 'newName1',
nested: {
value: 'newNested1'
}
};
$scope.myCollection[0] = newElem;
};
$scope.changeSecondLevel = function() {
var newElem = {
id: '1',
name: 'name1',
nested: {
value: 'newNested1'
}
};
$scope.myCollection[0] = newElem;
};
}]);
Run Code Online (Sandbox Code Playgroud)
你也可以在这个JSFiddle中实时运行它.
我确实理解AngularJS ng-options出于性能原因不会在其中观察复杂的对象.但有没有解决方法,即我可以手动触发重新渲染吗?有些帖子提到$timeout或$scope.apply作为解决方案,但我既不能利用也不能利用.
我以前用过的快速黑客是将你的选择放在ng-if中,将ng-if设置为false,然后在$ timeout为0后将其设置回true.这将导致angular重新呈现控件.
或者,您可以尝试使用ng-repeat自己渲染选项.不确定这是否有效.
是的,它有点丑陋,需要一个丑陋的解决方法。
该$timeout解决方案的工作原理是,如果您将该集合设置为 ,则为 AngularJS 提供更改以识别当前摘要周期中的浅层属性已更改[]。
下次有机会,通过$timeout,您将其设置回原来的状态,AngularJS 会识别出浅层属性已更改为新的属性并ngOptions相应地更新它。
我在演示中添加的另一件事是在更新集合之前存储当前选定的 ID。$timeout然后,当代码恢复(更新的)集合时,它可以用于重新选择该选项。
演示: http: //jsfiddle.net/4639yxpf/
var testApp = angular.module('testApp', []);
testApp.controller('Ctrl', ['$scope', '$timeout', function($scope, $timeout) {
$scope.myCollection = [{
id: '1',
name: 'name1',
nested: {
value: 'nested1'
}
}];
$scope.changeFirstLevel = function() {
var newElem = {
id: '1',
name: 'newName1',
nested: {
value: 'newNested1'
}
};
$scope.myCollection[0] = newElem;
};
$scope.changeSecondLevel = function() {
// Stores value for currently selected index.
var currentlySelected = -1;
// get the currently selected index - provided something is selected.
if ($scope.selectedOption) {
$scope.myCollection.some(function(obj, i) {
return obj.id === $scope.selectedOption.id ? currentlySelected = i : false;
});
}
var newElem = {
id: '1',
name: 'name1',
nested: {
value: 'newNested1'
}
};
$scope.myCollection[0] = newElem;
var temp = $scope.myCollection; // store reference to updated collection
$scope.myCollection = []; // change the collection in this digest cycle so ngOptions can detect the change
$timeout(function() {
$scope.myCollection = temp;
// re-select the old selection if it was present
if (currentlySelected !== -1) $scope.selectedOption = $scope.myCollection[currentlySelected];
}, 0);
};
}]);
Run Code Online (Sandbox Code Playgroud)