1

I am trying to call a service with parameters from my controller method and I get an error saying that it is not a function. Here is my code:

(function (){

angular.module('app.uploadedReleases')
        .controller('UploadedReleasesController', UploadedReleasesController)
        .controller('ModalController', ModalController);


UploadedReleasesController.$inject = ['$log', '$scope', '$modal', 'ReleaseService', 'TrackService'];
function UploadedReleasesController ($log, $scope, $modal, releaseService, trackService){

        vm.selectTrack = selectTrack;

       function selectTrack(album, track, index){

        trackService.currentTrack(album.slug, track.fileName).then(function(responseValue){
            vm.temp = responseValue;
        });
        vm.formTrack = vm.selected.track;
    }
}

Here is my service called trackService:

angular.module('app.services')
        .service('TrackService', TrackService);

TrackService.$inject = ['$http', '$q'];

function TrackService($http, $q){
    var trackService = {};

    var releasesUrl = 'http://localhost:8080/api/releases';
    trackService.currentTrack = currentTrack;

        function currentTrack(releaseSlug, trackSlug){
        var trackUrl = releasesUrl + '/'+ releaseSlug + '/' + trackSlug + '/track';
        var deferred = $q.defer();

        $http.get(trackUrl).then(function(trackResponse){
            return deferred.resolve(trackResponse);
        }, function(error){
            return deferred.reject({msg: 'Error while getting the current track details'})
        });
      return deferred.promise;
    }
}

Any idea why I would get the error in my controller: TypeError: trackService.currentTrack is not a function

Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
noobcoder
  • 11,983
  • 10
  • 39
  • 62

2 Answers2

3

@Pankaj Parkar's answer is correct in that you should be returning a promise from currentTrack in order to chain then in your controller.

However, to answer your question about the TypeError, you're mixing factory and service syntax here in TrackService.

To make it a factory, return a map of the exposed functions:

function TrackService($http, $q){
    var trackService = {};
    trackService.currentTrack = currentTrack;

    function currentTrack(releaseSlug, trackSlug){
        //...
    }

    return trackService;
}

and declare with .factory('TrackService', TrackService);.

To make it a service, add the exposed functions to this:

function TrackService($http, $q){
    this.currentTrack = currentTrack;

    function currentTrack(releaseSlug, trackSlug){
        //...
    }
}

and declare with .service('TrackService', TrackService);.

nickgraef
  • 2,397
  • 2
  • 22
  • 26
  • I already did figured out in my answer.. still good finding +1 – Pankaj Parkar Mar 24 '16 at 22:17
  • @nickgraef In my Service I am doing the same thing. `var trackService = {}` – noobcoder Mar 24 '16 at 22:19
  • 2
    @noobcoder it's not the same because in a service it needs to be bound to `this`, and in a factory, you need to return the trackService object – sdemurjian Mar 24 '16 at 22:21
  • @water42 aah I get it now. Thanks. Also, I realized I was not returning `trackService` in my service. +1 But I'd mark Pankaj's answer as correct. He did point that out first. I'll upvote your answer. Thanks guys – noobcoder Mar 24 '16 at 22:23
  • 1
    @noobcoder If you are still confused with it, you could do go through [this answer](http://stackoverflow.com/a/28262966/2435473) would you help you with understanding behind service/factory/provider. – Pankaj Parkar Mar 24 '16 at 22:26
1

Very 1st thing I'd say that is, you are creating a service then you should bind method to this context, rather creating object.

var trackService = {};

would change to

var trackService = this;

But returning custom object from service isn't wrong also. So in current situation you missed to returned it. At the end of your service code to add

return trackService 

Still confused how service & factory work, I'd recommend to readup on this answer


You should return a promise from trackService.currentTrack method which you had created in custom way.

trackService.currentTrack = currentTrack;
function currentTrack(releaseSlug, trackSlug){
    var trackUrl = releasesUrl + '/'+ releaseSlug + '/' + trackSlug + '/track';
    var deferred = $q.defer();
    $http.get(trackUrl).then(function(trackResponse){
        return deferred.resolve(trackResponse);
    }, function(error){
        return deferred.reject({msg: 'Error while getting the current track details'})
    });
    return deferred.promise; //returned promise
}

Rather you should be do your custom promise which is consider as anti-pattern to implement where you have promise returned by $http.get method, You should utilize that.

Refactored Version

trackService.currentTrack = currentTrack;
    function currentTrack(releaseSlug, trackSlug){
    var trackUrl = releasesUrl + '/'+ releaseSlug + '/' + trackSlug + '/track';
    return $http.get(trackUrl).then(function(trackResponse){
        return trackResponse;
    }, function(error){
        return {msg: 'Error while getting the current track details'};
    });
}
Community
  • 1
  • 1
Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
  • Thanks @Pankaj Parkar. I added the `return deferred.promise` and still have the same issue. – noobcoder Mar 24 '16 at 22:06
  • @noobcoder its really hard to understand what is `vm.selectTrack = selectTrack`? and then where does `vm.formTrack = vm.selected.track;` come from ? – Pankaj Parkar Mar 24 '16 at 22:11
  • They are just objects I defined like: `vm.formTrack = selectTrack` as a return value from the function selectTrack – noobcoder Mar 24 '16 at 22:14
  • 1
    @PankajParkar see https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md for a rundown on the controllerAs vm style – sdemurjian Mar 24 '16 at 22:15
  • @water42 Thanks for the link to JohnPapa's style guide. I was referring that only – noobcoder Mar 24 '16 at 22:16
  • @noobcoder could you look at updated answer please.. thanks ;) – Pankaj Parkar Mar 24 '16 at 22:20
  • @water42 LOL :D :D :D.. you got me wrong.. I didn't ask OP that what `vm` stands for & how it works?, I was just asking him, how code flow is going on.. I was lost when, I was trying to understand whats going on with code..so thats why I asked him about my confusion.. – Pankaj Parkar Mar 24 '16 at 22:29