I have a controller which has a function to get some alerts from an API and update a count on the front-end of my site which is bound to the alert.
Unfortunately the ng-bind
attribute I'm using doesn't seem to be updating the count live, even though a simple console.log()
is telling me that the actual alert count is being updated in the controller.
Front-end
<div class="modeSelector modeSelector_oneUp" data-ng-controller="MyLivestockController as vm">
<a class="modeSelector-mode" data-ui-sref="my-livestock">
<div class="modeSelector-type">Alerts</div>
<img class="modeSelector-icon" src="/inc/img/_icons/envelope-black.svg" onerror="this.src=envelope-black.png" />
<span data-ng-bind="vm.alertCount"></span>
</a>
</div>
Controller
(function() {
'use strict';
function MyLivestockController(userService) {
var vm = this;
vm.myLivestockNotification = {
isLoading: true,
hasError: false
};
vm.alertsNotification = {
isLoading: true,
hasError: false,
hasData: false
};
vm.deleteAlert = function(id) {
vm.currentAlert = void 0;
vm.alertsNotification.isLoading = true;
userService.deleteAlert(vm.user.id, id).then(function() {
// Remove the alert from our Array
vm.alerts = vm.alerts.filter(function(alert) {
return alert.id !== id;
});
// Refresh the alert count for the user
vm.getAlerts(vm.user.id);
vm.alertsNotification.isLoading = false;
vm.alertsNotification.hasError = false;
}, function() {
vm.alertsNotification.hasError = true;
});
};
vm.getAlerts = function(id) {
userService.getAlerts(id).then(function(alertData) {
vm.alertCount = alertData.length;
if (vm.alertCount > 0) {
vm.alertsNotification.hasData = true;
} else {
vm.alertsNotification.hasData = false;
}
vm.alerts = alertData;
vm.alertsNotification.isLoading = false;
vm.alertsNotification.hasError = false;
}, function() {
vm.alertsNotification.hasError = true;
});
};
// Init
(function() {
userService.getCurrentUser().then(function(data) {
vm.myLivestockNotification.hasError = false;
vm.myLivestockNotification.isLoading = false;
vm.user = data;
// Get alert count for the user
vm.getAlerts(vm.user.id);
}, function() {
vm.myLivestockNotification.hasError = true;
});
})();
}
angular
.module('abp')
.controller('MyLivestockController', MyLivestockController);
})();
Service
(function() {
'use strict';
function userService($q, $sessionStorage, $localStorage, $filter, user) {
var service = this;
service.getAlerts = function(id) {
var deferred = $q.defer();
user.alerts({ userID: id }, function(response) {
if (response.hasOwnProperty('data')) {
// Convert dates to valid Date
angular.forEach(response.data, function(alert) {
/* jshint camelcase: false */
if (alert.created_at) {
alert.created_at = $filter('abpDate')(alert.created_at);
/* jshint camelcase: true */
}
});
deferred.resolve(response.data);
}
else {
deferred.reject('DATA ERROR');
}
}, function(e) {
deferred.reject(e);
});
return deferred.promise;
};
angular
.module('abp')
.service('userService', userService);
})();
As you can see, I've got my getAlerts()
function being called every time an alert is deleted, using the deleteAlert()
function, but the <span data-ng-bind="vm.alertCount"></span>
on the front-end only updates after refreshing the page, where I'd like it to update live.
The ng-bind Directive in AngularJS is used to bind/replace the text content of any particular HTML element with the value that is entered in the given expression. The value of specified HTML content updates whenever the value of the expression changes in the ng-bind directive.
The ng-bind directive tells AngularJS to replace the content of an HTML element with the value of a given variable, or expression. If the value of the given variable, or expression, changes, the content of the specified HTML element will be changed as well.
Overview. The ngRepeat directive instantiates a template once per item from a collection. Each template instance gets its own scope, where the given loop variable is set to the current collection item, and $index is set to the item index or key.
Data binding in AngularJS is the synchronization between the model and the view. When data in the model changes, the view reflects the change, and when data in the view changes, the model is updated as well.
Your bind is not updating because you change the value of alertCount outside of digest cycle of your angular app. When you refresh your app, the digest runs and thus your value gets updated. Wrap the update of the variable in $scope.apply() like so:
$scope.$apply(function(){
vm.alertCount = alertData.length;
});
This will force digest and update the value live.
If you have more values that are updated outside of digest (any callback, promise etc) you can force digest cycle by calling:
$scope.$apply();
Hope it helps.
EDIT -----
Given your update with full code, I see that you are not injecting scope anywhere in your controller, the controllers I write usually start like that:
(function () {
var app = angular.module('mainModule');
app.controller('myController', ['$scope', '$myService', function ($scope, $myService) {
//logic
}]);
}());
EDIT -----
Here is a quick go I had on your code:
(function() {
'use strict';
var app = angular.module('abp');
app.controller('MyLivestockController', ['$scope', 'userService', function($scope, userService) {
var vm = {};
$scope.vm = vm;
vm.myLivestockNotification = {
isLoading: true,
hasError: false
};
vm.alertsNotification = {
isLoading: true,
hasError: false,
hasData: false
};
vm.deleteAlert = function(id) {
vm.currentAlert = void 0;
vm.alertsNotification.isLoading = true;
userService.deleteAlert(vm.user.id, id).then(function() {
// Remove the alert from our Array
vm.alerts = vm.alerts.filter(function(alert) {
return alert.id !== id;
});
// Refresh the alert count for the user
vm.getAlerts(vm.user.id);
vm.alertsNotification.isLoading = false;
vm.alertsNotification.hasError = false;
}, function() {
vm.alertsNotification.hasError = true;
});
};
vm.getAlerts = function(id) {
userService.getAlerts(id).then(function(alertData) {
vm.alertCount = alertData.length;
if (vm.alertCount > 0) {
vm.alertsNotification.hasData = true;
} else {
vm.alertsNotification.hasData = false;
}
vm.alerts = alertData;
vm.alertsNotification.isLoading = false;
vm.alertsNotification.hasError = false;
//important, this is promise so we have to apply the scope to update view
$scope.$apply();
}, function() {
vm.alertsNotification.hasError = true;
});
};
// Init
(function() {
userService.getCurrentUser().then(function(data) {
vm.myLivestockNotification.hasError = false;
vm.myLivestockNotification.isLoading = false;
vm.user = data;
// Get alert count for the user
vm.getAlerts(vm.user.id);
}, function() {
vm.myLivestockNotification.hasError = true;
});
})();
}]);
})();
The general idea is:
I think this should work for you :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With