Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS - ng-bind not updating

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.

like image 839
Alex Ryans Avatar asked May 08 '15 08:05

Alex Ryans


People also ask

How to bind value in AngularJS?

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.

When to use ng-bind?

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.

What is ng repeat end?

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.

What is bind in AngularJS?

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.


1 Answers

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:

  1. you create an app (angular.module)
  2. you create a controller in this app, with $scope injected
  3. any values you want to be updated on your view, you add to $scope
  4. if you have any $scope updates in a callback, event or promise, you wrap them in (or follow with) $scope.$apply call

I think this should work for you :)

like image 199
Daniel Gruszczyk Avatar answered Oct 15 '22 22:10

Daniel Gruszczyk