Reputation: 87
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
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
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