Controller in my default route gets executed after I logout. For loginG out I am just calling a server route using $http.post. As the thing is async, execution continues to go to my default route '\' but I don't want controller of my default route to execute until logout is complete. How can I create a link between logout and my controller? I know I can use promise to wait for Logout but this would be only in the function where I am calling logout. How can I wait in my controller for logout to finish?
Will appreciate any help.
Thanks.
Promises let you add a handler to their completion that's chainable:
// inside your controller action causing the log out:
$http.post("/logout").done(function(result){
// here you're logged out, the promise has its value
$location.href = "/"; // change route
});
Note: you can also wait in your router, but I assume from your question you'd like to avoid that.
Note2: I'd extract membership into a service.
Related
I'm working on app based react+mobx and as backend use the firebase.
Currently on the app start i need to check if user is logged in.
I'm doing it with firebase.auth().onAuthStateChange listener, but because it's async function - the first response always null.
So my current solution is display some loading message and put setInterval function with status checking in componentWillMount lifehook.
The question is - is there any more elegant solution to this issue?
Before you call firebase.auth().onAuthStateChange, modify your state to be something like: state.authenticatedUser: 'pending'. Have your observer change that state to real user info once it is called.
Have your components take into account state.authenticatedUser when rendering and render either "authentication pending" or "authenticate user"
I know that it is possible to wait for a promise to be resolved before loading a new location, but is there a way to wait for a promise before leaving the current location?
The use case is unlocking a resource corresponding to the page where the user is. We want to unlock it in any case, and that will need a call to the server. We don't want to leave the page if the corresponding resource is not locked.
Looking in the docs, i see that changing a route can be detected with signals, but there is no way to block a signal waiting for the result of a promise, as far as i know.
The only solution i can think about is:
Intercept the first route change signal, prevent default to prevent the location change
Do all asynchronous cleanup operations
Trigger a route change again, letting it finish this time
Any better/more idiomatic way? I am mainly interested in Angular 1 but also answers about Angular 2 are helpful
Currently i am going for something like:
'use strict'
angular.module('app')
.service('beforeLocationChange', function ($rootScope, $location) {
function makeRelative (location) {
var start = $location.absUrl().lastIndexOf($location.url())
return location.substring(start)
}
/* Careful! `fun` might be called several times before the
* listener gets deregistered, thus it has to be idempotent and
* possibly return a rejection for the calls after the first */
this.do = function (fun) {
var deregister = $rootScope.$on('$locationChangeStart', function (
event,
newUrl
) {
event.preventDefault()
fun()
.catch(function () {
throw 'The action before location change failed!'
})
.finally(function () {
deregister()
$location.path(makeRelative(newUrl))
})
})
}
})
This service can be injected in any controller and used within a page controller like this:
beforeLocationChange.do(function () {
return cleanup() // cleanup code has to return a promise
})
The catch is that cleanup() has to be idempotent. This is not a problem in my case and for cleanup code in general
Edit:
This does not cover the case of the user closing her browser or navigating away from the app without triggering an Angular route event, but i cannot find an effective way to handle that case. Both the Angular $destroy event and the DOM beforeunload event do not provide a way to stop and wait for asynchronous calls to terminate
Seems like child states are not waiting till parent state resolved. I am using resolve config option to load common data soon after user login to the system in a common parent state. Then all children can use it. Also I have a auth interceptor to check data has been loaded. I have created a simple example to demonstrate my problem. You don't need a username or a password to login and just see the logs. Application not navigate you to the home page because user data hasn't been loaded. I used one of a examples found in http://scotch.io to create this simple app. I wonder how to configure ui router, to child states wait till parents promises are resolved.
When authorize fires for app.home state on $stateChangeStart even data has not been loaded even I am loading data in app state which is the parent for app.home
function authorize(event, toState, toParams){
if(/^app/.test(toState.name)) {
console.log('toState', toState, 'cache', cache);
if(!cache.hasOwnProperty('user')) {
event.preventDefault();
$state.transitionTo('login');
console.log('data not loaded', event);
}
}
}
Example
http://plnkr.co/edit/hS8jKONk0ZfyJfE4r7Ty?p=preview
So a change was made to Controller::redirect and now it fires AFTER your controller action is called. So if you're wanting to redirect someone (that's not logged in for example) before logic is fired that is no longer possible. Does anyone know how to simulate the old 2.X behavior where a call to Controller::redirect would immediately stop everything and redirected?
The key is to return the $this->redirect() call, that will return a response object immediately from the controller that will make the Dispatcher understand that you want to terminante the request immediately:
return $this->redirect($url);
The redirect can be done from the controller action itself or any of the callbacks in the controller (beforeFilter, beforeRender, afterFilter ...). Returning the redirect value is also allowed from any of the component callbacks.
There are three possible ways to redirect user if he not logged in. I did it one of my app. First is using beforeFilter() of a controller. You could use like
public function beforeFilter(){
parent::beforeFilter();
if(empty($this->logged_in)){
//your redirect code or your logic
}
}
It executes at very first time when your controller action is being called.
Second you can create a class's constructor function. It executes also at very first.
public function __construct( $request = null, $response = null ) {
parent::__construct( $request = null, $response = null );
//Your redirect code if user not logged in
}
You can write your code in AppController beforeFilter(); But if you only want to prevent non logged in users to access some function, you should use Auth component allow function. Syntax is
$this->Auth->allow(array('action_name_1','action_name2'));
Paste this allow function in beforeFilter function. By using above tricks you can prevent user to access your logic if he / she not logged in.
I just had the same issue. And I ended up with good old header() function along with die()
header('Location: http://example.com/whatever');
die;
I'm working on a auth based application where the user must be logged to access to a certain routes of the website. I haven't found documentation on how to accomplish this so I worked on a idea on how to solve it.
This is my function to know if a user is logged or not:
App.filterAuth = function(navigateTo) {
navigateTo = typeof navigateTo !== 'undefined' ? navigateTo : '#';
if (App.logged == false) {
App.vent.trigger('navigate', navigateTo);
}
};
My idea is that when a user is logged sets the App.logged = true. Then, when my router tries to execute a concrete router I can just call App.filterAuth(). This actually works and doing some debugging I see that everything is triggered corrected.
The problem? For example I execute this on a protected route that loads a feed of images for a user. When App.filterAuth() is executed I see that it tries to navigate to # but the execution of this feed view isn't stopped and also the view associated to my # route is not triggered.
Any idea on how I can improve this function that makes it work correctly?
Thanks in advance!
This might not be an answer to question directly, but there is a backbone plugin which can help you with what you try to do: https://github.com/boazsender/backbone.routefilter
You can specify additional methods, which will be triggered before / after route code is processed. If you return false from before callback, router code won't be evaluated: https://github.com/boazsender/backbone.routefilter#returning-false-from-within-a-before-filter
So, you could create before filter, which could check, if route should be secured. If it is secured and user is not authenticated, you just return false and router code is not used.