dynamic subdomain with angularjs - angularjs

I am new to Angularjs and I would like to add dynamic subdomain such as sub.domain.com.
By changing sub, I would be able to ask the proper data from the server. However, the home page will still be the same.
sub1.domain.com and sub2.domain.com will have the same home.tpl.html page except that the data returned will be specific to the domain.
It will be the same for other pages too.
Is there a way to do that?

The main thing you need to look at is the $location service, in particular the $location.host() method. That will return you the full domain, from there it is easy to get the subdomain and use that.
You could even do a really simple service that you could inject anywhere to get access to the subdomain easily.
Something like:
app.factory('subdomain', ['$location', function ($location) {
var host = $location.host();
if (host.indexOf('.') < 0)
return null;
else
return host.split('.')[0];
}]);
Then you can use this as a simple injectable value in your controllers, directives, etc.
app.controller('SomeCtrl', ['$scope', 'subdomain', function ($scope, subdomain) {
// use subdomain same as any other variable
}]);

Subdomains are served by server, angular in turn serves hash/hashbang urls and knows nothing about subdomain.
U can have 3 subdomain, for example:
en.example.com (configured manually on server)|
de.example.com (configured manually on server)| -> example.com
it.example.com (configured manually on server)|
Each of them refers to the main example.com, but you wanna achieve something by using subdomains, for example i18n (with angular).
Thus, when someone connects to en.example.com (in fact, the request goes to example.com where you angular app is hosted) you can extract subdomain in angular(en in this case, see example in the post above) and translate you angular view.

Why no split by dots and count the elements of host()?
var host = $location.host();
var parts = host.split('.');
var subdomain = null;
// more than domain.cn, will always return the first
if (parts.length > 2)
subdomain = parts[0];
return subdomain;
hope it helps!

Related

window.open("url","_self") works well on localhost url, but not when I put it on a server

I have an angularJS frontend that I redirect to a third party payment gateway when a customer clicks on the Pay button.
I am currently using the following function to redirect to the payment gateway:
if(status.data.result == "true"){
var ref = window.open(url,'_self');
}
};
This code works well when I try it on localhost. But does not work when I put it on the ubuntu server.
Any ideas on why?
Regards,
Galeej
Try adding return false after var ref = window.open(url,'_self'); like
var ref = window.open(url,'_self');
return false;
return false will prevent from page submit and it may work this way to properly redirect on the same page.
May be your content security policy is blocking this url to load.
You can try using _blank instead of _self to see if that is the case.
Also it would be better to use $window, because angular.
Also are you using the fully qualified URL ?
The solution that worked for us was using window.location = url

Session Handling in Angular JS, with Spring MVC

I am creating a project in AngularJs at frontend and Spring MVC in backend.
Now assume when a used logged in and if he wants to update his information, for this i have created an api which request for emailid and update the rest object in database of that email id
Now i have some questions,
1.) I dont want to use CookieStore or others sessionStorage or localstorage (because of my personal vulnerability experience and also i want to use session only) in Angular, how can i do it in angular with Spring MVC.
2.) How can i retrieve the email id from session to update data?
3.)If a user goes to another page how can i maintain that session in another page, how can i check that session is there and user is authentic to see the page
Read a lot about it but unable to find the exact solution with session. Answer over there is manage it by cookieStore.or localstorage, Please help
Let's try and see what is happening here using cookies is the right way to this, you may think it is not safe but is the safest way to do it. With cookies you will be sharing the same session in all tabs, so you can handle in all tabs and share it.
There is also an alternative option and is using URL rewriting, quoting #vanje in this question in stackoverflow
the session is only identified via a URL parameter containing the session ID. So every internal URL of your web application has to be enhanced with this parameter using the method HttpServletResponse.encodeURL(). If you are using a web framework like Wicket, chances are good that this is already done for you.
Lets go now with the Angular JS - Spring MVC approach:
There is no need to access the session within the Angular JS front-end, if you need to use it and you are using JSP you may use scriplet to retrieve the information openening a <%= session.getAttribute("user") %> , but as I said there is no need to do this. You may call your function, and retrieve this information in your controller in Spring.
You have a controller in angular JS that calls with http to your REST controller in Spring such like this. assuming that you save your user first in session:
$scope.getUserInfo= function () {
$http.get(appContextPath +'/rest/getuser/').success(function (data) {
$scope.user= data;
});
};
You may have a request mapping for the URL above:
#RequestMapping(value = "/rest/getuser", method = RequestMethod.GET)
#ResponseBody
public User getUserInfo (HttpSession session) {
User nUser = session.getAttribute("user");
return nUser;
}
I think the best way is to create a method in your AngularJS controller and then call it.
Java code:
#RequestMapping(value = "/menu/get", method = RequestMethod.GET, headers="Accept=*/*")
public #ResponseBody Empleado showMenu(HttpSession session) {
Empleado empleado = (Empleado) session.getAttribute("empleado");
return empleado;
}
AngularJS code:
angular.module('myModule')
.controller('myMenuController', ['$scope', '$http'
function($scope, $http){
getEmpleadoInfo = function () {
$http.get(myContextPage + '/menu/get')
.then(function(data) {
$scope.empleado = data;
})
}
getEmpleadoInfo();
}]);
This way, when you load the page, the object will be loaded on the scope.

Making a logged in user-variable in AngularJS+laravel

I'm trying to make a global variable called theUser which contains the userinfo if logged in.
I have tried putting this in my SPA php file:
app.value('theUser', '<?php echo Auth::user(); ?>');
And it works but only after refreshing page. (Login happens via angularjs logic + a $http request to auth/login which returns userinfo if logged in)
In my angular auth app, I have done this:
var login = $http.post("auth/login", sanitizeCredentials(credentials)).success(function(data) {
theUser = data;
$rootScope.theUser = theUser;
});
And that works, but only when the user logs in. If I refresh, theUser is empty. And I can't get these two solutions to work together. I probably need another approach.
All I want is an user variable that I can access from anywhere in my app,
which is set if the user logs in, or have been logged in before. Using Laravel 5.1.
Here is my auth app service js: http://pastebin.com/HcdLaZcD
How can I make this work?
Why dont you use PHP-Vars-To-Js-Transformer by Laracasts. Then whenever a User logs in, you could set a Session variable auth_user and then get that variable to JavaScript as shown below (in your Laravel AuthController#login):
...
\Session::put('auth_user', \Auth::user());
JavaScript::put([
'theUser' => \Session::get('auth_user')
]);
...
And when the User logs out: \Session::forget('auth_user');
theUser variable will be available anywhere in your JavaScript (or you can Namespace it also, check the Github link above).
on top of the page under script tag
window.user = <?php echo Auth::user(); ?>
and
app.value('theUser',window.user);
app.run(function ($rootScope, theUser) {
$rootScope.theUser = theUser;
});
For accessing the logged in user from your JavaScript files, you may try something like this (Create a view composer, also layouts.master dictates layouts/master.blade.php):
View::composer('layouts.master', function($view) {
$user = null;
if(Auth::check()) {
$user = Auth::user();
}
$view->with('authUser', $user);
});
In the master layout try this (So User variable will be available as JS object if the user is logged in):
<head>
<script>var User = {{ $authUser or 'undefined' }}</script>
</head>
This is just an idea, implement it according to your need. Also, you may use a namespace like App.user. I wrote an article about this lasr year, you may
check it here. Btw, it was for Laravel 4.x.
.
We have made use of html5 local storage to overcome this once the user is logged in, you just put the user's info on html5's local storage (works on all browsers, even mobile).
It has some drawbacks which you have to overcome, and also have some control on your routes filters to avoid someone loading page they shouldn't be allowed to see.
But I'm afraid my answer applies better to our solution and I don't think this answer is perfect but might guide you in a better solution. Our app publishes an API for angular's use and this angular is somewhat empowered with some extensions to ease routing.

Modify or access angular interceptors after config phase

Is it possible to access / modify $http interceptors after the config phase? I'm debugging an app that only breaks in production due to being deployed on a different server, so unfortunately I can't change the interceptor code locally and figure out what's going on.
If it's not possible to access / modify the interceptors, perhaps it'd be possible to replace $http. Here's an example of replacing a hypothetical service:
var inj = angular.element('body').injector(),
oldGet = inj.get,
mockService = { secret: 'shhh' };
inj.get = function(str) {
if (str === 'some-service') {
return mockService;
} else {
return oldGet.apply(inj, arguments);
}
};
However, I'm not sure how I'd go about creating a new $http service (into which I could pass in the modified interceptors). I can't grab the $httpProvider, either.
Perhaps bootstrapping a new ng-app on a separate part of the page would work? Then I could grab the $http service and replace it, like above.
Other ideas:
With reference to: Right way to disable/remove http interceptors in Angular? , it does not seem like I can access the interceptors array if I don't hold on to it in the config phase.
Perhaps I can use grease monkey to inject something that runs in the config phase.
Thank you!

AngularJS HTML5 mode degrade to full page reloads in lieu of hashbang

By enabling HTML5 mode in AngularJS, the $location service will rewrite URLs to remove the hashbang from them. This is a great feature that will help me with my application, but there is a problem with its fallback to hashbang mode. My service requires authentication, and I am forced to use an external authentication mechanism from my application. If a user attempts to go to a URL for my app with a hashbang in it, it will first redirect them to the authentication page (won't ever touch my service unless successfully authenticated), and then redirect them back to my application. Being that the hash tag is only seen from the client side, it will drop off whatever parts of the routes come after by the time they hit my server. Once they are authenticated, they may re-enter the URL and it will work, but its that one initial time that will cause a disruption to the user experience.
My question is then, is there any way to go from $location.html5Mode(true) to the fallback of full page reloads for un-supportive browsers, skipping the hashbang method of routing entirely in AngularJS?
The best comparison of available implementations of what I'm aiming for would be something such as browsing around folders on github.com. If the browser supports rewriting the URL without initiating a page refresh, the page will asynchronously load the necessary parts. If the browser does not support it, when a user clicks on a folder, a full-page refresh occurs. Can this be achieved with AngularJS in lieu of using the hashbang mode?
DON'T overwrite the core functionality.
Use Modernizr, do feature detection, and then proceed accordingly.
check for history API support
if (Modernizr.history) {
// history management works!
} else {
// no history support :(
// fall back to a scripted solution like History.js
}
Try to wrap $location and $routeProvider configuration in browser's HTML5 History API checking, like this:
if (isBrowserSupportsHistoryAPI()) {
$location.html5Mode(true)
$routeProvider.when(...);
}
Also may be you need to create a wrapper to $location if you use it to change path.
(Sorry for terrible english)
Why not handle the un-authenticated redirect on the client side for this situation? I'd need to know a bit more about exactly how your app works to give you a more specific solution but essentially something like:
User goes to a route handled by AngularJS, server serves up the AngularJS main template and javascript
User is not authenticated, AngularJS detects this and redirects to the authentication page
You could have something in the module's run block for when the AngularJS application starts:
module('app',[])
.configure(...yadda...yadda...yadda...)
.run(['$location', 'authenticationService', function($location, auth) {
if (!auth.isAuthenticated()) {
$location.url(authenticationUrl)
}
});
I've subbed in a service which would find out if you were authenticated somehow, up to you how, could be checking a session cookie, could be hitting your API to ask. Really depends on how you want to continue to check authentication as the client application runs.
You can try and override the functionality of the $location service. The general idea would be to rewrite the URL according to whether someone is already authenticated or not, or just use a single approach (without hashbangs) for all URLs, regardless to whether html5mode is on or not.
I'm not sure that I fully understand the use-case so I can't write the exact code that you need. Here is a sample implementation of how to overrides/implements and registers the $location service, just making sure that hashbang is always eliminated:
app.service('$location', [function() {
var DEFAULT_PORTS = {
ftp: 21,
http: 80,
https: 443
};
angular.extend(this, {
absUrl: function() {
return location.href;
},
hash: function(hash) {
return location.hash.substr(1);
},
host: function() {
return location.host;
},
path: function(path) {
if (!path) {
return location.pathname;
}
location.pathname = path;
return this;
},
port: function() {
return location.port ? Number(location.port) : DEFAULT_PORTS[this.protocol()] || null;
},
protocol: function() {
return location.protocol.substr(0, location.protocol.length - 1);
},
replace: function() {
return this;
},
search: function(search, paramValue) {
if (search || paramValue) {
return this;
}
var query = {};
location.search.substr(1).split("&").forEach(function(pair) {
pair = pair.split("="); query[pair[0]] = decodeURIComponent(pair[1]);
});
return query;
},
url: function(url, replace) {
return this.path();
}
});
}]);

Resources