I have been playing with angularjs for couple of days and like it so far. I am trying to build a chrome extension which attaches a small widget below every gmail message when the user is on gmail.com. So far so good. As part of authentication code, I handle 401 error in this way. Whenever there is a 401 error, I use $location.path( "/login" ) to redirect the user to the login screen/template. This changes browser address bar which seems to be the default behavior. So, if the current address was https://mail.google.com/mail/u/0/, it becomes https://mail.google.com/mail/u/0/#/login. But mine is not standalone app, its more like widget that attaches to a div when on gmail.com site. My app should not mess with the browser address bar. I am now starting to think if I can really use angularjs for my app as I am going against the default behavior. Should I use angularjs at all?
I also posted it here https://groups.google.com/forum/?fromgroups#!topic/angular/TrT54r_IYmg
You can emit/broadcast events on rootScope and subscribe to them in your login directive.
Here is little clue http://www.espeo.pl/2012/02/26/authentication-in-angularjs-application
it uses interceptors to catch 401
myapp.config(function($httpProvider) {
var interceptor = ['$rootScope','$q', function(scope, $q) {
function success(response) {
return response;
}
function error(response) {
var status = response.status;
if (status == 401) {
var deferred = $q.defer();
var req = {
config: response.config,
deferred: deferred
}
scope.requests401.push(req);
scope.$broadcast('event:loginRequired');
return deferred.promise;
}
// otherwise
return $q.reject(response);
}
return function(promise) {
return promise.then(success, error);
}
}];
$httpProvider.responseInterceptors.push(interceptor);
});
And simplest directive could be this
myapp.directive("loginForm",function($http){
return function(scope,element,attrs){
element.hide();
scope.$root.$on('event:loginRequired', function(event) {
element.show();
});
scope.login=function(){
// You can set controller for this directive, but I skiped that part for sake of simplicity
var payload = $.param({username: scope.username, password: scope.password});
var config = {
headers: {'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'}
}
$http.post('/some/login/url', payload, config).success(function(data) {
if (data === 'AUTHENTICATION_SUCCESS') {
element.hide();
}else{
alert("username or password was wrong, please try again");
elements.find("form").reset(); // reset form, or you coud reset just password field
}
});
};
};
});
Now, directive in action
<div login-form>
<form ng-submit="login()">
<label for="username">Username</label>
<input type="text" id="username" ng-model="username"/>
<br />
<label for="password">Password</label>
<input type="password" id="password" ng-model="password" />
<hr/>
<input type="submit" value="Login" />
</form>
</div>
Please note code above is not tested, probably there is some misspell or something. But let me know if you have trouble implementing this, I will try to take some time and effort to make it work.