Damian
Damian

Reputation: 87

How can I pass data from a service into my controller?

Okay so right now I am messing around with the ionic framework and learning angularJS at the same time. I just came across $q and async calls, but I just can't seem to get it right. I want to be able to parse a JSON file which I already have set up using GetJsonSpecials then pass that to GetData which will then pass it to my controller SpecialsCtrl so I can attach it to $scope. I know I am not understanding the promises correctly because everything inside SpecialService undefined. I can get the data perfectly fine from the other two serivces, but when I try passing it to SpecialService it all just seems to crumble which in turn ends up as undefined in my controller. Maybe I am not going about this the right way? Are there any best practices of doing this kind of thing?

angular.module('starter.controllers', [])

.controller('SpecialsCtrl', function ($scope, SpecialService) {
  $scope.specials = SpecialService.all();
  console.log("Specials Controller: Got Data", $scope.specials);
})

//Create methods to access the specials inside the controller in which we inject this in
.factory('SpecialService', function (GetData) {
  var specials = GetData.getSpecials();
  console.log("DATAAAA: ", specials);
    return {
      // Return all specials
      all: function () {
        console.log("Inside return with specials: ", specials);
        return specials;
      },
      getSpecialWithId : function (specialId) {
         // Simple index lookup
         return specials[i];
      }
    }
  }
})

.factory('GetData', function(GetJsonSpecials) {
  return {
    getSpecials : function() {
      GetJsonSpecials.retrieveData().then(function (data) {
        console.log("Got the JSON data", data);
        return data;
      }, function (status) {
        alert("Error getting specicals", status);
        console.log("Error getting specicals", status);
      });
    }
  }
})
//Asynchronously get the specials from the json file
.factory('GetJsonSpecials', function ($q, $http) {
  return {
    retrieveData : function() {
      var deferred = $q.defer();
      $http.get('js/specials.json').success(function (data, status) {
        deferred.resolve(data);
      }).error(function (status) {
        deferred.reject(status);
        console.log("Error in handling json!");
      });
      return deferred.promise;
    }
  }
})

The reason I have this overly complicated is because in the end I want to be able to share the data to another controller which will display that specific specials' properties in a new view.

.controller('DetailCtrl', function ($scope, $stateParams, JsonSpecials, $firebaseAuth) {
  $scope.id = parseInt($stateParams.specialId);
  $scope.special = JsonSpecials.getSpecialWithId($scope.id);
})

Upvotes: 0

Views: 1171

Answers (2)

logee
logee

Reputation: 5077

There are a few problems here. The main issue being that angularjs promises are asynchronous and you're trying to use them in a synchronous manner.

First off, you having an extra } after your SpecialService definition.

In your SpecialService:

.factory('SpecialService', function (GetData) {
   var specials = GetData.getSpecials();

This will be nothing because your GetData.getSpecials() returns nothing.

If you were to fix GetData.getSepcials to return:

getSpecials : function() {
  return GetJsonSpecials.retrieveData().then(function (data) {
    console.log("Got the JSON data", data);
    return data;
  }, function (status) {
    alert("Error getting specicals", status);
    console.log("Error getting specicals", status);
  });
}

then back in your SpecialService, you need to change how you get the data back.

var specials = GetData.getSpecials();

won't give you your data either. It will be a promise because it is asynchronous. So it needs to be

  GetData.getSpecials().then(function(data) {
    return data;
   });

Also, as Matt as pointed out, in your retrieveData definition, you're creating an unnecessary promise. So

retrieveData : function() {
  var deferred = $q.defer();
  $http.get('js/specials.json').success(function (data, status) {
    deferred.resolve(data);
  }).error(function (status) {
    deferred.reject(status);
    console.log("Error in handling json!");
  });
  return deferred.promise;
}

is the same as:

retrieveData : function() {
    return $http.get('js/specials.json').error(function (status) {
        console.log("Error in handling json!");
        return status;
    });
}

Upvotes: 2

Matt Herbstritt
Matt Herbstritt

Reputation: 4862

It seems you are over complicating things a bit. You're passing data around factories for no clear reason. I think those three factories could be combined into just one. Maybe try something like..

index.html

<!DOCTYPE html>
<html ng-app="foobar">

  <head>
    <link rel="stylesheet" href="style.css">

  </head>

  <body>

    <div ng-controller="SpecialsCtrl">
      {{specials}}
    </div>

    <div ng-controller="AnotherController">
      {{specials}}
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
    <script src="script.js"></script>
  </body>

</html>

script.js

angular.module('foobar', [])

.controller('SpecialsCtrl', function ($scope, JsonSpecials) {

  JsonSpecials.retrieveData().then(function(data){
    $scope.specials = data;
  });

})

.controller('AnotherController', function ($scope, JsonSpecials) {

  JsonSpecials.retrieveData().then(function(data){
    $scope.specials = data;
  });

})


//$http returns a promise anyway so you don't need $q
.factory('JsonSpecials', function ($http){


  return {

    retrieveData : function() {
      return $http
        .get('js/specials.json')
        .error(function (status) {
          console.log("Error in handling json!");
        });
    }

  }

});

Upvotes: 0

Related Questions