duffn
duffn

Reputation: 3760

AngularJS returning data from service to view

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. enter image description here

Upvotes: 1

Views: 1475

Answers (1)

ProxyTech
ProxyTech

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

Related Questions