VVV
VVV

Reputation: 7593

Service returning unexcepted data

I've just started to learn angularjs and I've literally spent 4 hours on this and I still don't know what's wrong.

I have a service that gets some data from a server.

Service.js

(function() {
  "use strict";
  angular.module('appName')
       .service('MyService', function($http, $q, $location) {        
          var service = this;
          service.data = false;

          var deferred = $q.defer();

          //makes the api call to get that data
          service.load = function() {
            $http({
              method: 'GET',
              url:'/url',
              headers: { 'Content-type': 'application/json' },
              cache: false
            })
            .then(function(response) {
              service.data = response.data;
              deferred.resolve(service.data);
            },function() {
              deferred.reject("Failed to get data");
            });

            return deferred.promise;
          };

          //checks if the data has already been loaded. If not, load it...
          service.loaded = function() {            
            if (!service.data) {
              service.load()
              .then(function(response) {
                  deferred.resolve(response);
                }, 
                function(response) {
                  deferred.reject("Failed to load data");
                }
              );
            }
            else {
              console.log('Already have data');  
            }

            return deferred.promise;
          };

          //reset the data (for when we log out)
          service.destroy = function() {
            service.data = false; 
          };


        return {
          loaded: service.loaded,
          destroy: service.destroy,
          getStuff: function () {
            return service.data.stuff;
          }
        };

     });
})();  

In my controller, I call the service like this

Controller.js

(function() {
  "use strict";
  angular.module('appName')
         .controller('MyController', function($scope, $http, MyService) {
            var controller = this;

            $scope.stuff = [];

            MyService.loaded()
                      .then(
                        function(response) {
                          $scope.stuff = MyService.getStuff();
                          controller.init();
                        }, 
                        function(response) {
                          console.log('Error', 'Could not get customers');  
                        });


            controller.init = function() {
              // do something;
            };

         });
})();

Here's a little background on my app.

First Screen User enters username and password and sends query to server. If server returns true, user is redirected to app via $location.url('url');.

Second Screen Controller appears on screen, calls Service. Service returns data and Controller is populated correctly.

So far everything works.

when I click on my logout button, I destroy the data in the service.

When I log back in with another username and password, I am still shown the data from the previous user even though I see in my console that the correct json has been sent by the server. It's as if the service.data doesn't get updated the second time around. .service is a singleton... could it be that deferred = $q.defer(); need to be reset?

Please note that if I refresh the browser on my second screen (after a login) I'm shown the correct information.

I appreciate any help.

Upvotes: 1

Views: 58

Answers (2)

charlietfl
charlietfl

Reputation: 171690

could it be that deferred = $q.defer(); need to be reset?

Yes, you are only only creating one instance for the life of the app not an instance per api call.

In fact the use of $q for your $http calls is totally un-necessary and is considered an ant-pattern.


First lets fix it using $q so it would work. You need to create a new promise object for every use :

var deferred = $q.defer(); // your one time only object

//makes the api call to get that data
service.load = function() {

Should be:

//makes the api call to get that data
service.load = function() {
   // new deferred object each use
   var deferred = $q.defer();

However $http itself returns a promise so all you really need is to return $http not create a new promise:

 service.load = function () {
     // return the $http promise
     return $http({
         method: 'GET',
         url: '/url',
         headers: {
             'Content-type': 'application/json'
         },
         cache: false
     }).then(function (response) {
          service.data = response.data;
          // instead of `deferred.resolve()` return the data
          return service.data
     }, function () {
         // error handling code
     });
 };

For your loaded() method, create a new $q each time

Upvotes: 1

Dmitri Algazin
Dmitri Algazin

Reputation: 3456

service.loaded is wrong logic, If loaded create deferred resolve with data, otherwise return load() itself:

service.loaded = function() {            
    if (service.data) {
       var deferred = $q.defer();
       deferred.resolve(service.data);
       return deferred.promise;
    } else {
       return service.load();
    }
};

I would keep 'var deferred = $q.defer();' separate instances inside each service method, do not share across all service calls.

Upvotes: 1

Related Questions