Reputation: 3760
I'm having difficulty returning data from my service to my view in AngularJS. Here is what I have at the moment. I also tried something like this, but had the same result. AngularJS Load Data from Service
Controller
.controller('ClassCtrl', ['$scope', '$stateParams', 'ClassService', function($scope, $stateParams, ClassService) {
$scope.data = ClassService.getClass($stateParams.siteID, $stateParams.classDate, $stateParams.classID);
$scope.$apply(); // I thought this my do it?
}])
Service
.factory('ClassService', ['$http', function ($http) {
return {
getClass: function(parm1, parm2, parm3) {
var classData = {};
var url = 'http://somesoapservice.com';
var sr = '<?xml version="1.0" encoding="UTF-8"?>' +
'<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' +
'moresoapstuff' +
'</soap:Body>' +
'</soap:Envelope>';
$http({
method: 'POST',
url: url,
data: sr,
headers: {
'Content-type': 'text/xml',
'SOAPAction': 'http://somesoapservice/soapaction'
}
}).
success(function (data, status, headers, config) {
var classDetail = $(data).find('Class');
var staffFirst = classDetail.find('Staff').find('FirstName').text();
//alert(staffFirst); // This displays the first name. Great!
classData = {
staffFirst: staffFirst
};
return classData;
}).
error(function(data, status, headers, config) {
alert('Error!');
});
return classData;
}
}
}])
View
<view title="navTitle" right-buttons="rightButtons">
<content has-header="true" has-footer="true">
First Name: {{data.staffFirst}}
</content>
</view>
I can see staffFirst in an alert when put inside the service, but cannot get it to appear in my view.
Upvotes: 1
Views: 1475
Reputation: 1145
I've just started learning AngularJS and this was one of those gotcha's that I missed coming from a desktop synchronous-based development background.
The issue here is that your $Http call within your service is firing off asynchronously. Thus your code line return classData;
at the end of your getClass
is going to return before the $Http call. Therefore only the empty initialised value ({}
) of your object will be returned and that's all your view will have to access.
What you need, is to hook into the promise capability of the Angular framework. A promise essentially allows you to place a method callback on itself so that when an asynchronous operation is complete, your code logic is assured to fire in a synchronous manner.
Your code would need to change as follows:
We first need to inject the promise library into your factory
.factory('ClassService', ['$http','$q' function ($http, $q) {
Your factory return will be:
getClass: function(parm1, parm2, parm3) {
var classData = {};
var url = 'http://somesoapservice.com';
var sr = '<?xml version="1.0" encoding="UTF-8"?>' +
'<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap
/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' +
'moresoapstuff' +
'</soap:Body>' +
'</soap:Envelope>';
var deferred = $q.defer(); // our promise object
$http({
method: 'POST',
url: url,
data: sr,
headers: {
'Content-type': 'text/xml',
'SOAPAction': 'http://somesoapservice/soapaction'
}
}).
success(function (data, status, headers, config) {
var classDetail = $(data).find('Class');
var staffFirst = classDetail.find('Staff')
.find('FirstName').text();
//alert(staffFirst); // This displays the first name. Great!
classData = {
staffFirst: staffFirst
};
deferred.resolve(classData); //At this point our promise is "resolved"
return deferred.promise;
}).
error(function(data, status, headers, config) {
deferred.reject("Error!");
return deferred.promise;
});
}
Your controller
.controller('ClassCtrl', ['$scope', '$stateParams', 'ClassService', function($scope, $stateParams, ClassService) {
ClassService.getClass($stateParams.siteID, $stateParams.classDate, $stateParams.classID)
.then(function(data){
$scope.data = data; //This callback will only execute once the $http success has completed.
})
.fail(function(error){
alert(error);
});
}])
Upvotes: 1