Atul Chaudhary
Atul Chaudhary

Reputation: 1133

Update controller variable on Updating Angular factory variable

Hi I have got one question. I have got one object as following in my Factory

User: {
   EmailAddress: ""
}

whenever i make http call I want to update that User.EmailAddress whith returned value. What is the best way of doing it in within the factory? so that at controller level I can just bind my $scope.Email to factory variable. This is what I am doing right now

GetLogOnModel: function () {
    if ($location.path().indexOf("login") == 1) {
        var promise = $http.get(config.headers.url + "LogOn").then(function (response) {
            // The return value gets picked up by the then in the controller.
            User.EmailAddress=response.data.Email;
            return response.data
        });
        return promise;
        // Return the promise to the controller
    }
}

And in Controller

AccountFactory.GetLogOnModel().then(function (data) {
  $scope.logOnModel = data;
}, function (err) {
  console.log(err.reason);
  alert(err.reason);
});

Upvotes: 4

Views: 14210

Answers (2)

gkalpak
gkalpak

Reputation: 48211

Primitive types (such as strings) are not bound by reference. So you can't bind a scope property to EmailAddress directly and expect it to get automatically updated.
Objects on the other hand are bound by reference, so you could do something like this:

app.factory('AccountFactory', function (...) {
  ...
  var User = {
    ...
    EmailAddress: null
  };

  function getLogOnModel() {
    $http.get(...).then(function (response) {
      User.EmailAddress = response.data.Email;
    });
  }

  // Init model (or leave it for the controller to init it)
  getLogOnModel();

  return {
    ...
    User: User,
    getLogOnModel: getLogOnModel
  };
});

app.controller('someCtrl', function (..., AccountFactory) {
  $scope.user = AccountFactory.User;
  // Now you can reference `$scope.user.EmailAddress`
  // and it will be kept in sync with `AccountFactory.User.EmailAddress`
});

Upvotes: 14

codef0rmer
codef0rmer

Reputation: 10530

It should be pretty straight forward. Either you bind the instance of the service or just the email property to the $scope.

Here I'm just updating the email after 5 secs.

myApp.factory('myService', function($http, $timeout) {
    return {
        email: '[email protected]',
        updateEmail: function() {
            var self = this;
            $timeout(function() {                
                $http.get('/echo/json/').success(function() {
                    self.email = '[email protected]';
                });
            }, 5000);
        }
    };
});

1st Method: Bind the entire service on the scope as:

function MyCtrl($scope, myService) {
    $scope.myService = myService;
    myService.updateEmail();
});

<div ng-controller="MyCtrl">
  myService: {{myService.email}}! 
</div>

2nd Method Just create a custom $watch for email updates:

function MyCtrl($scope, myService) {
    $scope.email = myService.email;
    myService.updateEmail();

    $scope.$watch(function() { return myService.email; }, function(newVal, oldVal) {
       $scope.email = newVal;
    });
}

<div ng-controller="MyCtrl">
  $scope: {{email}}
</div>

I would recommend the first method because it requires only one $watch to update the DOM i.e. for {{myService.email}} whereas the second method requires two $watches i.e. one to update the $scoped model ($scope.$watch) and other to update the DOM as {{email}}.

Demo: http://jsfiddle.net/HB7LU/3015/

Upvotes: 7

Related Questions