Reputation: 12801
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
Upvotes: 1
Views: 1274
Reputation: 136144
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'};
});
}
Upvotes: 1
Reputation: 2417
@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);
.
Upvotes: 3