0

I've been facing a trouble while working with Factory/Service. I've created an AjaxRequests factory for all of my AJAX calls. My factory code is

.factory('AjaxRequests', ['$http', function ($http) {
                return {
                    getCampaignsData: function () {
                        var campaigns
                        return $http.get(url).then(function (response) {
                            campaigns = response.data;
                            return campaigns;
                        });

                    }
                }
            }])

I've created another service in which I am injecting this factory. My service code

.service('CampaignsService', ['$rootScope', 'AjaxRequests', function ($rootScope, AjaxRequests) {
     this.init = function () {
     this.camps;
     AjaxRequests.getCampaignsData().then(function (response) {
       this.camps = response.campaigns;
       console.log(this.camps); // It is showing data
     })
     console.log(this.camps); // But it is not working :(
    };
   this.init();

}])

And in my controller

.controller('AdvanceSettingsController', ['$scope', 'CampaignsService', function ($scope, CampaignsService) {
                $scope.CampaignsService = CampaignsService;
            }
        ])

I've read this article to learn promises but it is not working here. I can directly achieve it in controller and it's been working fine. But it consider as a bad coding standard to make controller thick. But when I use service and factory I stuck. My question is why I am not getting ajax data to use in my whole service ? I need to use CampaignsService.camps in my view template as well as in my whole rest script but every time I get undefined. What is happening here? I've asked the same question before but couldn't get any success. Some one please help me to understand about promises and why I am getting this type of error if I'm working same ? This type of question has already been asked before but it was working in controller. May be I am stuck because I'm using it in a service.

A big thanks in advance.

Community
  • 1
  • 1
Vineet
  • 4,525
  • 3
  • 23
  • 42
  • 2
    In my experience you don't need `CampaignsService`, You should directly use `AjaxRequests.getCampaignsData().then(function (response) { $scope.camps = response.campaigns; })` in your controller – Satpal May 28 '15 at 10:55
  • Okay, so what I could do instead. Actually I've already wrap up my complete code in this service but before I was working on static data. I stuck when I use service – Vineet May 28 '15 at 10:57

1 Answers1

4

This is not a bug or some tricky functionality. Just like in any other AJAX implementation, you can only access the response data in AngularJS's $http success method. That's because of the asynchronous nature of Asynchronous JavaScript And XML.

And what you have is working.

.controller('AdvanceSettingsController', ['$scope', 'AjaxRequests', function ($scope, AjaxRequests) {
        $scope.camps = [];
        AjaxRequests.getCampaignsData().then(function(data) {
             $scope.camps = data;
        });
    }
])

And then bind camps:

<div ng-repeat="camp in camps>{{camp.name}}</div>

What's bad in your implementation is that instead of grouping related stuff in services you are writing a big AjaxRequests service for everything. You should have a CampaignsService that has a getData method and inject that in your controller.

Why is this working? Because $http does a $scope.$apply for you, which triggers a digest cycle after the data is loaded (then) and updates the HTML. So before the then callback that ng-repeat is run with [] and after it it's again run but with data from the response because you are setting $scope.camps = data;.

The reason <div ng-repeat="camp in CampaignsService.camps>{{camp.name}}</div> does not work is because of function variable scoping.

The this reference inside of your then callback is not the same as the this reference outside of it.

This will work and uses the common var self = this trick:

var self = this;
this.camps = [];
this.init = function () {
    AjaxRequests.getCampaignsData().then(function (response) {
        // here "this" is not the one from outside.
        // "self" on the other hand is!
        self.camps = response.campaigns;
    });
};
Community
  • 1
  • 1
Sergiu Paraschiv
  • 9,929
  • 5
  • 36
  • 47
  • Thanks a lot to share this useful information. I got your point and I'll change my code structure as per you've mentioned but here is my last question. Why $scope.CampaignsService = CampaignsService; not works in controller ? – Vineet May 28 '15 at 11:14
  • It is working with another functions except $http service. If my another function changes any object and I am using this object in view, then by using above line the digest cycle automatically start. – Vineet May 28 '15 at 11:16
  • Thank you so much Mr. Sergiu. – Vineet May 28 '15 at 11:58