I've been struggling with this all morning. I'm trying to call a Service from within my config($httpprovider). I've read a lot of people explaining that Services are not yet available during config. I get that, but my service should only be called from within the interceptor, which is at runtime.
I found a semi-solution that manually injected the Service manually like below, but it's not working for me, since it seems a completely new instance of the Service is being created, and I want to keep using the same instance throughout the app (since it stores a messageQueue array). Any suggestions?
.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push(function ($q) {
return {
'responseError': function (rejection) {
//responses 300 and up are errors
//Manually inject service from the myServices module, since it is not yet known when .config is called
var $injector = window.angular.injector(['myServices']);
var MessageService = $injector.get('MessageService');
MessageService.setMessage("We were unable to load all necessary data. We're terribly sorry! Please try reloading this page or contact us if the problem isn't solved.");
}
};
});
}])
You can register your interceptor as a service using a factory, according to angularjs 1.2.2 documentation, so it should be provided with the right dependencies, using the following syntax :
.config(['$httpProvider', function ($httpProvider) {
$provide.factory('myHttpInterceptor', ['MessageService', function (MessageService) {
return {
'responseError': function (rejection) {
//responses 300 and up are errors
MessageService.setMessage("We were unable to load all necessary data. We're terribly sorry! Please try reloading this page or contact us if the problem isn't solved.");
}
};
}]);
$httpProvider.interceptors.push('myHttpInterceptor');
}]);
Related
I have configurations.js file which having
var configurationModule = angular.module('configuration', ['restangular', 'notification']);
configurationModule.factory('clientConfigSvc', function (notificationMgr, $interpolate, $injector) {
function getConfig(configKey) {
return getNestedPropertiesByString(activeEnvironment, configKey);
}
}
and having another javascript file with below code
angular.module('ds.coupons').factory('CouponsREST', ['Restangular', 'SiteConfigSvc', 'settings',function (Restangular, siteConfig, settings, configurationModule) {
configSvc.getConfig('services.baseUrl'); /// need to call this function
}
Actually i want function configSvc.getConfig inside second angular factory
Yes After tired of trying lots of solution, today morning working on moving train got idea to fix, dont know if its correct way but its working. but still looking for correct fix if mine was not correct as per angularjs practise.
Here is my solution.
1. I added configuration module in app.js alogn with other
window.app = angular.module('ds.app', [
'restangular',
'ui.select',
'ui.router',
'ds.shared',
'ds.utils',
'ds.i18n',
'configuration']);
I added clientConfigSVC in my factory where i want to use configuration function
angular.module('ds.coupons')
.factory('CouponsREST', ['Restangular', 'SiteConfigSvc','settings', 'clientConfigSvc',
function(Restangular, siteConfig, settings, clientConfig) { }
and then inside CouponsREST factory with function clientConfig.getConfig() i am getting value
Let's suppose I have a simple service:
angular.module('myModule')
.factory('myService', ['$http', function($http) {
return $http.get('/something');
}]);
Now whenever I inject the service into a controller, the router waits for the promise to resolve before changing the route, which is exactly what I want.
However, there doesn't seem to then be a way to return other data from the service. What if the service needs to also provide some methods? How can I do this while still maintaining the dependency behavior described above?
You can use the Angular implementation to promise pattern $q to create a promise which will be resolved when the $http.get gets resolved, and resolve the main one with the data coming from your HTTP resource and other data and functions:
angular.module('myModule')
.factory('myService', ['$http', '$q',
function($http, $q) {
var deferred = $q.defer();
$http.get('/something').then(function(data) {
deferred.resolve({
data: data,
doStuff: function() {}
});
});
return deferred.promise;
}
]);
BTW, I'm not sure if the result of some HTTP request is exactly a service at all. It seems like the whole GET should be encapsulated by a function of your myService service, and call it in some controller, service, directive or wherever you need to call it, and provide a continuation with .then there instead.
Or, if you're using UI Router, you might be able to call a service function which returns a promise form a route resolver and it will do the job while implementing your services in the right way.
Probably it's just as easy as I think it is, but I cannot really find an answer to my question on the internet, so I hope you guys know the answer just by looking at a small piece of my code.
Problem: I'm using the UI router in Angular and it loads the template before all the data is loaded. So all input fields receive the correct values AFTER the template is already loaded. So the input fields are empty for a second or two....
I think my resolve is not as it should be:
So my ui-router code looks something like this (check the resolve object):
$stateProvider.state('teststate', {
url: '/test/',
templateUrl: 'app/page/template.html',
controller: 'testCtrl',
resolve: {
access: ["Access", function(Access) { return Access.isAuthenticated(); }],
UserProfile: 'UserProfile'
}
});
Now the controller contains the promise to get some data from an API url:
function TestCtrl($scope, $state, $stateParams, TestService) {
TestService.get($stateParams.id).then(function(response) {
$scope.data = response;
});
}
Now the service (which connects to the API) should return the promise to the Controller:
TestService.factory('TestService', ['Restangular', function(Restangular) {
var factory = {};
factory.get = function(id) {
return Restangular.one('api/test', id).get();
}
return factory;
}]);
Now, could the problem be, that because the TestService.get() (which connects to the API) within the Controller, gets executed NOT before the template is loaded, because it's not inside the resolve object? So the UI router doesn't resolve the call to the API? I'm just curious or I should move all methods which make API calls, to the resolve object of each stat inside the $stateProvider.
I could run a lot of tests, but if someone just directly knows the answer by just looking at this question, it helps me a lot.
Your assumptions are all correct.
If you resolve the TestService.get in routing config the data would be readily available to controller as an injectable resource
If you don't want your controller to run and your template to show before all your API calls are finished, you have to put all of them inside ui-routers resolve.
However, if API requests can take a little while it seems better UX to transition to the new page immediately and show some kind of loading indicator (e.g. block-ui) while your API call is running.
I am working on an angular project and I am using $ resource for the first time. I currently have just as a test to get data out of my database a service that has one call to $resource
Here is my service:
(function() {
"use strict";
angular.module("commonServices")
.factory("ptaResource",
["$resource", ptaResource]);
function ptaResource($resource) {
return $resource("http://localhost:55928/api/excercises", {}, { 'query': { method: 'GET', isArray: true } });
}
})();
My question is this. I have a lot of calls to make to various controllers and methods within those controllers. I cant wrap my head around how to structure a service that allows me to call it with an endpoint listed
I tried doing something like this:
var services =[
getExercises: getExercises,
doSomething: doSomething
];
return service;
function getExercises (){
return $resource request here
}
But that did not work, I have looked on line but any tutorial is only exposing one of each type of request. I am going to have several get requests to controllers, some with different query strings. I will be querying different controllers as well. The purist in me tells me that all of this belongs in one place.
What would be a good method for doing this one large service with a way to call each request individually. Should I break them into a service per web api controller. Any input would be appreciated.
Thanks,
John
If you wanted to wrap your resources in a service, you could do something like this:
angular
.module('commonServices', ['ngResource'])
.factory('ptaResource', ['$resource', function($resource) {
return $resource('http://localhost:55928/api/excercises/:excerciseId', {
excerciseId: '#id'
});
}])
.service('CommonService', ['ptaResource', function(ptaResource) {
return {
getExercises: function() {
return ptaResource.query().$promise;
}
};
}]);
Then you could call it like so:
angular
.module('app', ['commonServices'])
.controller('SomeController', ['$scope', 'CommonService', function($scope, CommonService) {
$scope.exercises = CommonService.getExercises();
// or
CommonService.getExercises().then(function(exercises) {
$scope.exercises = exercises;
}).catch(function(err) {
// handle error here
});
}]);
As a bit of background - I have created a simple interceptor to handle 401's in angular. All the data in the application is retrieved from the server using breeze.
Below is the 401 interceptor I am using
app.factory(serviceId, ['$q', '$location', function ($q, $location) {
var authInterceptorServiceFactory = {};
var _responseError = function (rejection) {
if (rejection.status === 401) {
$location.path('/login');
}
return $q.reject(rejection);
}
authInterceptorServiceFactory.responseError = _responseError;
return authInterceptorServiceFactory;
}]);
Whenever I attempt to navigate to a page that requires the user to be authenticated it works as expected and I am redirected to the login page. My console however is littered full of errors and it looks rather unprofessional, is there anyway to get rid of or suppress these errors?
I don't think Breeze is doing this. Search breeze.debug.js and you'll find no references to the console or a logging component. When a $http call returns anything but a 200, breeze rejects the promise so that layers up the line can decide what to do. In many cases it delegates back to Angular. All of this is evident when you read the breeze code.
I suspect that you need to configure Angular to suppress this console output.
Do update us when you figure it out.