Globals across Angular services? - javascript

Can I define global variables or functions that can be accessed by all of my Angular service modules?
For example, I have several services that make http requests to various endpoints of the same url root. I would like to be able to change this root.
My service modules look like this.
var host = 'http://my-api.com';
return {
get: function(id) {
return $http({
url: host + '/contacts/' + id,
method: 'GET'
});
},
...
switchHost: function(url){
host = url;
}
});
So I can call ContactService.switchHost('http://new-url') in my Controllers to update this particular Service.
I would like to have some sort of Root Service where I coul define host and switchHost globally.
Note: The use case here is that some of our clients will be accessing our company API, and others will be self-hosting their resources.

i suggest you to create an interceptor which will digest an angular value like this.
angular.module('...')
.value('HOST', 'http://www.fu.bar.com/')
.factory('InterceptorFactory', function (HOST) {
return {
request: function(config) {
config.url = HOST + config.url;
return config;
}
};
})
.config(['$httpProvider',function($httpProvider) {
$httpProvider.interceptors.push('InterceptorFactory');
}]);
Whenever you call the $http service, the factory will be called and will add your host.
If you want to update the host, you just need to inject in any block the value and update it.

Thanks for the responses. I just did something like this.
angular.module('app.services').factory('RootService', function($http) {
return {
switchHost: function(url){
this.host = url;
},
host: 'http://app.apiary-mock.com'
}
});
This way the client can just type in a url on the settings page and the root will change, which is what I want.

Related

How to protect server views and client views using loopback

I'm trying to protect my application's views based on roles. In laravel the solution is simply adding a middleware as part of the route parameters. Also would like to accomplish the same functionality on the client side using an Angular SPA app. Sorry I think these are two questions in one, anyways.
https://laravel.com/docs/5.1/authentication#protecting-routes
Any simple solution to accomplish this?
In Angular you can implement the same logic in an Interceptor something like this..
app.factory('ApiInterceptor', function() {
return {
'request': function(config) {
//check config.url against users roles somehow
disallow = doesTheUserHaveTheCorrectRoles(config.url);
//disallow the request to the API
if(disallow){
alert('No!');
return false;
}else{
return config;
}
}
}
}
Check the documentation on HTTP Interceptors https://docs.angularjs.org/api/ng/service/$http
Or you could do the same thing with a run block and do something when the location changes;
app.run(function ($rootScope) {
$rootScope.$on("$locationChangeStart", function (event, next, current){
disallow = doesTheUserHaveTheCorrectRoles(next);
//disallow access to the next location
if(disallow){
alert('No!');
return false;
}else{
return config;
}
});
});
https://docs.angularjs.org/guide/module

Angular JS and Cross Origin Requests

I am just playing around with angular JS and wiring it up to some restful web services I have implemented. I have moved onto using the $resource module provided by angular and have a simple question (I hope). In my code below I am making a request to a spring boot micro service I have written and am wanting to know the best way of accessing the URL.
So is there another way of calling the resource that is cross origin rather than having to write the line below. Is there something like /customer/greeting I could use but then how would I specify the different port as my angular app resides on localhost:8000?
http://localhost\:9001/customer/greeting //this is a spring boot application
My full code for the service.js is below this resides on localhost:8000 and is a node JS server.
'use strict';
/* Services */
var phonecatServices = angular.module('phonecatServices', ['ngResource']);
phonecatServices.factory('Phone', ['$resource',
function($resource) {
return {
pDetail: $resource('phones/:phoneId.json', {}, {
query: {method: 'GET', params: {phoneId: 'phones'}, isArray: true}
}),
cDetail: $resource('http://localhost\:9001/customer/greeting', {}, {
query: {method: 'GET'}
})
};
}]);
When people normally implement do they have lots of http://balh blah when it goes cross origin? Is there a pattern that can be applied here?
Thanks in advance.
You can do this way:
Make function
var getCrossOriginUrl=function(portNo){
var crossOriginPath="http://localhost\:"
return crossOriginPath+portNo+"/";
}
So now you can call this way:
$resource(getCrossOriginUrl(9001)+'customer/greeting',{}, {
query: {method: 'GET'}
})

How to inject services to monitor authentication and storage status?

I'm using Angular.js to build a client side application with Restangular.
The problem is, I implemented a digest authentication with a wsse header which i have to generate at each request to my REST Server.
I saw that Restangular provide a function : addFullRequestInterceptor().
So now, i'm trying to use it inside my RestangularProvider to configure it in this file restangular.js :
// Config Restangular
app.config(function(RestangularProvider) {
RestangularProvider.setBaseUrl(applicationConfig.SERVER_URL);
RestangularProvider.setDefaultHeaders({'Content-Type': 'application/json'});
RestangularProvider.addFullRequestInterceptor(
function (element, operation, route, url, headers, params, httpConfig) {
// Here is my header generation.
$http.defaults.headers.common['X-WSSE'] =
TokenHandler.getCredentials(
AuthHandler.authentication.user.username,
AuthHandler.authentication.secret);
return {
element: element,
headers: headers,
params: params,
httpConfig: httpConfig
};
});
});
But i have an injection problem and i can't find out how to inject my TokenHandler service & my AuthHandler service to be able to know if the user is already loggedin or not and if he has localstroage or not.
Thanks for the help ;)
The problem is that in the .config phase the services, like AuthHandler and TokenHandler are not yet instantiated, so you need to instantiate them (and their dependencies) manually with $injector (which is injectable into config blocks):
app.config(function(RestangularProvider,
$injector,
AuthHandlerProvider,
TokenHandlerProvider) {
var AuthHandler = $injector.instantiate(AuthHandlerProvider.$get);
var TokenHandler = $injector.instantiate(TokenHandlerProvider.$get);
//...
});

How to cache http in Angular until parameters changed?

Is it possible to cache some http until parameters used in url change:
app.factory('dataService', function ($http,$rootScope) {
return {
getData: function () {
return $http.get(rest.getData
+ $rootScope.number + "/" + $rootScope.blb
).then(function (result) {
return result.data;
});
}
}
});
So, when $rootScope.number changes in controller, I need to call http again, until then it should be cached. Is it possible and how?
Angular's $http has cache built in. Set cache as true in your $http request options:
$http.get(url, {cache: true}).then(...);
If you want to cache data you can do it in a number of ways.
You can cache it inside your service also.
Here is post which should help you.

Angularjs $resource url intercept url encoding

I'm working on a sort of file-manager application that connects to a RESTFUL file api.
On the angular app, each file and directory is an instance of angular $resource using the file-object property relativePathName as resource id .
js
var File = $resource(url + '/:type/:id', {id: '#relativePathName', type: '#type'}, {…});
The problem is, when updating a file resource, the relativePathName parameter gets url encoded, e.g. / becomes %2F which causes the server to intercept the request before it hits the actual API (I assume the server treats this as a physical address and of returns a 404 response). The API is capable of treating whole url segments as a single param, so basically it'd treat path/to/file as a uri parameter of http://myapp.com/api/files/create/path/to/file and not as a different uri.
My question is, is there a way to modify the request url after it's being generated by the private Router instance inside of the resource constructor? If so, how (found nothing on this in the docs)?. What would be a possible solution? passing relativePathName as a parameter instead of declaring it as the resource id (which would require modifying the API)?
Thanks in advance.
Thomas
Using $resource is not the one stop shop for RESTful service calls, it is merely a convenience service for api's that are structured in a certain way. If $resource cannot do what you need, just create your own service using a mix of $resource and $http that that fits the api you are trying to call.
In our app we wanted a different URL for getByName requests, so we override the resource address with the URL parameter of the action getByName like so:
myapp.factory('ListGroup', ['$resource',
function($resource) {
return $resource(
'/API/List/:Id',
{
Id:'#Id',
Name:'#Name'
},
{
getByName: {method: 'GET', url: '/API/List/Group/:Name', isArray: true}
}
);
}
]);
My question is, is there a way to modify the request url after it's being generated by the private Router instance inside of the resource constructor?
I'm not sure about inside of the resource constructor but you can use interceptors to programatically alter route urls after they have been generated by $resource.
structure
hooks.config.js
hooks.factory.js
hooks.module.js
hooks.module.js
module.exports = angular
.module("app.hooks", [])
.factory("hooks", require("./hooks.factory.js"))
.config(require("./hooks.config.js"));
hooks.config.js
module.exports = ["$httpProvider", function($httpProvider) {
$httpProvider.interceptors.push("hooks");
}];
hooks.factory.js
module.exports = ["$q", "$location", function($q, $location) {
var basePrefix = "/api/v1";
return {
//invoked on every http request
request: function(request) {
request.url = interpret(request.url);
return $q.when(request);
}
};
function interpret(str) {
//if requesting an html template, don't do anything
if (str.indexOf(".html") > -1)
return str;
//if you're accessing the api, append the base prefix globally here
else
return basePrefix + str;
}
}];

Categories