Getting Last Active URL Prior to Logout in Angular 2 App - javascript

In my Angular 2 app I am trying to store the last active URL prior to a user logging out, so that that url can be re-loaded after the user re-logs in. However, this is proving problematic. Consider this logout function from my authenticationService:
logout()
{
let lastUrl = this.getActiveUrl();
console.log('Url before logout: ', lastUrl);
this.apiService.logout();
}
Notice here that "lastUrl", which calls this.getActiveUrl(), which looks like this:
getActiveUrl()
{
let activeUrl = this.router.routerState.snapshot['url'];
console.log('activeUrl: ', activeUrl);
return activeUrl;
}
...appears BEFORE this.apiService.logout(). But, nevertheless, what gets printed to the console for "lastUrl" is "/login". But that's the URL where I end up immediately after logging out.
So, help me understand this:
If this is synchronous, why doesn't the correct URL print here? What am I missing? And how can I get the active url immediately prior to logout firing and re-directing to '/login'?
EDIT: After a commenter's suggestion, I tried assigning to localStorage instead of a local variable, like so:
logout()
{
localStorage.setItem('returnUrl', JSON.stringify(this.router.routerState.snapshot['url']));
this.apiService.logout();
}
But when I dig that value out with localStorage.returnUrl, I still get "/login".

First off, many thanks to #Sam for the localStorage suggestion. I should have thought of that. So, in the end, all I needed to do was make use of RouterStateSnapshot from my canActivate() function in my AuthGuardService, and save that value to localStorage. Then I just retrieve that value to plugin in on re-authentication and re-login:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
{
// Get route content id
let contentId = Object.getPropertyValueAtPath(route, 'data.contentId');
// Store last active URL prior to logout, so user can be redirected on re-login
localStorage.setItem('returnUrl', JSON.stringify(state.url));
// DO OTHER STUFF...
}
In my login component I just get that value to pass in...
login(response)
{
this.loading = true;
this.authenticationService.login(this.model.username, this.model.password, function (results)
{
if (results.data && results.ok === true)
{
this.returnUrl = JSON.parse(localStorage.getItem('returnUrl'));
this.router.navigate([this.returnUrl || '/']);
console.log('ReturnURL Value is: ', this.returnUrl);
this.reset();
}
else
{
this.alertService.error(null, response);
this.loading = false;
}
}.bind(this));
}

It is happening synchronously. However, you are logging an object pointer. By the time you look at the object in the console, it has changed because the route has changed.
I suggest using local storage to store the router snapshot. This will not have the same pointer issue that you see in the console.

Related

How do we read dynamically changing value from express session and display the value on angular front end

I have been working with JavaScript for sometime but recently had to use Angular (v7). I am stuck with a situation where I've a session value set in express session and the value is very dynamic. I am not able to display this value in my view in real-time.
This is my first question on SO, and I know I can be very vague, but please let me know if you think you can help me. I can elaborate more if needed.
I have made a Observale variable in my component, and a service is there to call the express controller, which in turn calls express model where a session value is read and returned.
Now this call is happening only for one time, but I want this call to return session value automatically, whenever it changes.
app.component.html
<button *ngIf="sessionValue$ | async as sval">
{{sval.status}}
</button>
app.component.ts
this.sessionValue$: Observable<any>;
ngOnChanges(change) {
this.intialise();
this.sessionValue$ = this.sessionService.get();
}
sessionService.ts
url = environment.appUrl + 'session';
get(): Observable<any> {
return this.http.get<any>(this.url + '/status');
}
express.session.controller.js
exports.status = function (req, res) {
try {
sessioModel.get(req.session, function (result) {
res.status(200).send(result);
});
} catch (error) {
logger.error(error);
}
}
express.session.model.js
exports.get= function (session, handleResponse) {
var sessionValue= session['variableMe'];
const retVal= sessionValue['nowValue'];
if (!retVal) {
handleResponse({ status: "" });
} else {
handleResponse({ status: retVal });
}
};
I expect the value on html page to change every time session variable changes its value.
I would recommend using sockets, this would allow you to communicate in real-time between the front end and backend without having to do a service call every time. This is a pretty good library with good documentation on how to get set up.
The backend is a bit trickier to get set up, so if you have trouble be sure to reach out for help.

const Variables not updating without window reload

I am trying to have my login page redirect to my main page.
I do this by using:
this.props.history.push("/userdashboard");
This works but on The main page there are const variables pulled in from Constants.js, which contains USER_ID, set from local storage:
let user_id = null;
try {
user_id =
window.localStorage.getItem("user_info") &&
JSON.parse(window.localStorage.getItem("user_info")).user_id;
} catch (err) {
console.error("Error Parsing user_info user_id");
}
const USER_ID = user_id;
export { USER_ID };
and then imported with
import { USER_ID} from "../constants/Constants";
The problem is that, these constants are still null and do not contain the new information until the page is reloaded.
I would like to be able to do this without using location.reload, as I want the user to be pushed into a specific page sometimes.
This is coming from my login page which waits for the action to finish then pushes
this.props.loginFunc(login_data).then(() => this.completeLogin());
completeLogin() {
this.props.history.push("/userdashboard");
}
I cannot figure out a way to refresh this const data. Also I am not entirely sure why these constants are used for getting the item from local storage every time, which is not expected, and is used in enough places that it would be a pain to refactor.
I'm not sure that const vs let (vs var, I guess) makes a difference, here. What is important that the localStorage is being read once. When is it supposed to be updated after the one initial reading? I don't see that piece of code.
Put this line
user_id = window.localStorage.getItem("user_info") && JSON.parse(window.localStorage.getItem("user_info")).user_id;
where the script should check for updates, if you expect updates at runtime.
The whole point of constants is that they cannot be reassigned. So each time the Constants.js is imported, it will always use the previous const value.
You've already got a let user_id variable, simply export that
let user_id = null
try {
user_id = window.localStorage.getItem("user_info") && JSON.parse(window.localStorage.getItem("user_info")).user_id
}
catch(err) {
console.error("Error Parsing user_info user_id")
}
export {
USER_ID: user_id,
}

LocalStorage for React Login Screen with reCaptcha

Hello everyone i try to use localStorage when user try to login my website if he/she try more than 2 times reCaptcha appear only way is click checkbox in reCaptcha but if user refresh the page reCaptcha is gone because of my state attempNumber. I want to keep attempNumber in localStorage and use firstly localStorage if user try more than 2 , when refresh page , reCaptche should be there .
I tried like that, but it is not working.If you help me i will be so appreciate for that . Thank you everyone .
this.state = {
email: '',
password: '',
load: false,
attempCount: 0,
};
handleLogin(e) {
const {
email, password, recaptcha,
} = this.state;
const cachedHits = localStorage.getItem(this.state.attempCount);
if (cachedHits) {
this.setState({ attempCount: JSON.parse(cachedHits) });
return;
}
this.setState({ attempCount: this.state.attempCount + 1 });
e.preventDefault();
e.stopPropagation();
this.props.doSignIn({ email, password, recaptcha });
return false;
}
well, code you have added doesn't show how and where you are setting value in localStorage.
I assume you will update localstorage in login button click event something like this
localStorage.setItem('clickCount', this.state.attempCount );
assuming your this.state.attempCount is incremented by 1 on click
Now to get its value use
let count = localStorage.getItem('clickCount');
if(count > 2){
// show Captcha
}
Without seeing your doSignIn code it is hard to tell what is happening with your localStorage, but your call to localStorage in the code you pasted is passing your attemptCount as the key. You should use a string as the key such as 'attemptCount' rather than a key that will change with your state changes.
That might not be all your problem, but is what I noticed so far.
I guess you're trying to get the value under key 0 if you take a look at the documentation here. Try to save it under a key you now as localStorage.setItem('attempts', this.state.attempCount) and then localStorage.getItem('attempts').
When you do a getItem I believe it will return a string, so do a parse parseInt(localStorage.getItem('attempts'), 10) before using it for any operation.
There are two issues with the code:
value is never beign set in localstorage.
First time when handleLogin is called, below line
const cachedHits = localStorage.getItem(0);
it tries to fetch value for zero which is never stored in local storage and it returns null(i.e cachedHits= null),
then it skips the if part and sets attempCount in state to 1 and show captcha.
next time when handleLogin is called,
const cachedHits = localStorage.getItem(1); which is again not present in cache and cachedHits= null and so on...
so, you need to set value in localStorage against some key like and in getItem use that key

Reloading current user doesn't refresh emailVerified state in Firebase Authentication

I've been trying to fix the problem for a whole day and couldn't make it work. I'm getting irritated, firebase docs are such a mess it's insane..
So I'm trying to implement email verification on my React app. I wen't with the docs, and google do send the email, I can click it, it's all good.
But, the email verified state doesn't change at all, and believe me I've went through all the stackoverflow topics.
firebase.auth().doSignInWithEmailAndPassword(email, password)
.then(() => {
console.log(firebase.auth().currentUser);
firebase.auth().currentUser.reload()
.then(() => {
console.log(firebase.auth().currentUser);
})
})
So I've found i need to reload the user to see the changes applied, tho they just won't work no matter what I do.
Both console logs return email.verified = false at all times.
I'm hopeless, anyone have any idea on how to make this work?
I was wondering whether me setting up custom domain as a verification link has to do anything with that? I'm testing on localhost, link is linking to live website.
Please help :(
The method you should call is signInWithEmailAndPassword, so remove the "do" in the function call:
firebase.auth().signInWithEmailAndPassword(email, password)
.then((credential) => {
const currentUser = credential.user;
console.log(firebase.auth().currentUser);
firebase.auth().currentUser.reload()
.then(() => {
console.log(firebase.auth().currentUser);
})
}).catch((err) => {console.error("Problem with sign in ", err);}
Use the credential returned from this function and assign its user value to currentUser to validate that the user has been authenticated.
Lastly, remember to add a catch at the end whenever you use then. In this case, err will contain a property err.code that will tell you why the user could not be authenticated.
I had the same problem. You need to reload your current user using a timer and then listen to user changes (not auth changes) in a Streambuilder. As soon as the user clicks the link they will be redirected to your main page.
Use a Streambuilder to listen to changes to the user:
StreamBuilder<User?>(
stream: FirebaseAuth.instance
.userChanges(), // monitor the changes to the user
builder: (ctx, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return LoadingScreen(); // show loading screen while loading
if (snapshot.hasData && !snapshot.data!.emailVerified) {
return VerifyEmailScreen();
} // if not verified show the verify email screen
if (snapshot.hasData) {
return MainScreen();
} // if logged in already show main screen
return OnboardingScreen(); // if not logged in already show the auth screen
},
),
In your VerifyEmailScreen() create a timer in it's initState like this:
void initState() {
Timer.periodic(Duration(seconds: 5), (timer) {
FirebaseAuth.instance.currentUser?.reload();
});
super.initState();
}
I hope it helps your problem.
Cheers

Retrieving URL From Just Prior to Logout in Angular 2 App

I am trying to obtain the last active url prior to logging a user out of my Angular 2 app, so that when they log back in it will redirect them to that component/page. The thing is, while I'm able to obtain the active url with this.router.routerState.snapshot['url'] -- this always provides me with the result /login -- which is the url they're re-directed to right AFTER logout takes place. What I need to do is find a way to get the url JUST PRIOR to logout happening. I tried doing this in my logout function in my authenticationService:
logout()
{
let activeUrl = this.router.routerState.snapshot['url'];
console.log(activeUrl);
this.apiService.logout();
// remove user from local storage to log user out
sessionStorage.removeItem('currentUser');
console.log('User successfully logged out');
// Trigger event
this.change.emit(this);
}
But even though the activeUrl is being console.logged before this.apiService.logout() is called (see order of operations in above function), I still end up getting /login logged to the console. Is this to be expected? How can I get around this?
EDIT: After some reflection it occurs to me now that the problem may be that I'm calling the logout() function from within the ngOnInit life cycle hook of my login component - so at that point '/login' is going to be the result regardless:
ngOnInit()
{
this.authenticationService.getActiveUrl();
this.authenticationService.logout();
}
So the pertinent question becomes: how do I capture the active URL just prior to being logged out?
In the Angular documentation it states that RouterState contains RouterStateSnapshot so to me it seems that the toString() is called when you log it to console but you still keep a reference in your activeUrl which may change.
Try:
let activeUrl = this.router.routerState.snapshot['url'].toString();

Categories

Resources