Reputation: 9407
I fetch data using $http and refresh it (server polling) every 1 second :
(function tick(){
$http.get('http://api.openweathermap.org/data/2.5/group?id=524901,703448,2643743&units=metric')
.success(function (data) {
console.log('tick');
$scope.cities = data.list;
$timeout(tick, 1000);
});
})();
This data is displayed in a table using a ng-repeat directive and I show a bootstrap dropdown menu:
<tr ng-repeat="city in cities">
<td>{{city.name}}</td>
<td>
<div class="dropdown">
<button type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</button>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
<li><button>Buttons</button></li>
<li><button>Are closed</button></li>
<li><button>When $scope variable</button></li>
<li><button>is refreshed</button></li>
</ul>
</div>
</td>
</tr>
The problem is when I open the dropdown menu it is closed as soon as the function tick() run.
I've tried to compare data from $http.get and scope and not update the $scope in case they're the same. But even though as soon as $http.get is triggered the dropdown closes even if I do not update the scope variable.
I would like to be able to poll and display the dropdown menu without closing. It would be reasonable though if the dropdown closes when data is really changed but not on each poll.
Here is a plunker showing the effect : http://plnkr.co/edit/yqYsQ32XaAhZEsD2XWMu?p=preview
Upvotes: 3
Views: 603
Reputation: 7958
Instead of constantly updating the array and adding the objects, you should instead just update the existing object or if there are any new items then add them to the array. When you attempted to do this you kept changing the array value instead of just changing the object.
(function tick(){
$http.get('http://api.openweathermap.org/data/2.5/group?id=524901,703448,2643743&units=metric')
.success(function (data) {
if ($scope.cities.length === 0) {
$scope.cities = data.list;
}
else{
for (var i = 0; i < data.list.length; i++) {
var dataCity = data.list[i];
var found = false;
for (var j = 0; j < $scope.cities.length; j++) {
var city = $scope.cities[j];
if (dataCity.id === city.id) {
found = true;
if (!angular.equals(city, dataCity)) {
angular.copy(dataCity, city);
}
break;
}
}
if (!found) {
$scope.cities.push(dataCity);
}
}
for (var k = 0; k < $scope.cities.length; k++) {
var cityToCheck = $scope.cities[k];
var cityFound = false;
for (var l = 0; l < data.list.length; l++) {
var dataToCheck = data.list[l];
if (dataToCheck.id === cityToCheck.id) {
cityFound = true;
break;
}
}
if (!cityFound) {
$scope.cities.splice(k, 1);
k--;
}
}
}
$timeout(tick, 1000);
});
})();
Upvotes: 2
Reputation: 7257
You can check if the objects are equivalent using angular.equals
if(!angular.equals($scope.cities, data.list)) {
$scope.cities = data.list;
}
Upvotes: 1