How to use *ngIf correctly? - javascript

I want to use *ngIf in my angular project. I use app.component.html to handle login page and as well as dashboard. So I want to hide dashboard before user login to the website. After user logged to the system I want to show the dashboard.
So I use *ngIf to handle this. I use following code to handle the case.
In my app.component.html I use following div to show when ever user is not log to the system.
<div class="login-page" *ngIf="!isLog()">
... go some code here...
</div>
And following div is use to show the dashboard after user is log to the system.
<div class="main-dashboard" *ngIf="isLog()">
... go some code here and router outlet as well ...
<router-outlet></router-outlet>
</div>
Finally in my app.component.ts file is use isLog() method to check whether user is logged or not.
isLog(){
// Use to back end api to check user log
var log : boolean = false;
// If User is Log
// Use back end api to handle this
log = true;
return log;
}
But the issue is when user try to log to the system for first time this code structure works fine for that case. But after user log to the system if user refresh the page for little time (0.5 ms > time) system shows the login page and suddenly shows the current page.
I think this is because every time user refresh the page website try to check user is log. During that time isLog() method return false so website shows login page for that time.
After isLog() return the valid value it means true. Then it shows the dashboard.
But I want to avoid this case. After user log to the system I don't want to show login page even for little time. Because user get confused.
How can avoid this case? Is there are any possible way to handle this type of issue?? OR recommended way???

If that's the case, try to store this info in sessionStorage which will persist the data for that tab and you wont have to wait for server response.
Also, as a side note, using *ngIf="isLog()" is not a good approach. You can try to put console.log in isLog() and you'll see it getting triggered periodically. That's because of change Detection cycle of angular which works on all the expressions assigned to template, and since *ngIf has function associated to it, that function (isLog()) is executed.
Its better if you can evaluate this value on ngOnInit and assign it some variable which will be used as a flag to check *ngIf condition

Of course it depends on your needs but the best practise is making the login page a seperate component and use Route Guards to protect the routes.
If having it in the same page and using ngIf is enough for your requirements which means you have a small application and it is not likely to expand, it is fine. The problem you experience is well explained by #Shashank Vivek in his answer.

Related

Reloading or refreshing page removes authorization in vue.js

I'm using social authentication using the vue-google-oauth2 library. It works fine as I am able to authenticate my self and I receive a token from the backend too.
When initially I log in, and by using a function that is part of the vue-google-oauth2 library that I'm using to check if it says that I'm authorized or not, it gives the following response in my browser's console:
this.$gAuth.isAuthorized
true
When I then refresh my browser page, and since I've placed a debugger command in my code, and I print the same function again,
I get the following response:
this.$gAuth.isAuthorized
false
What can I do to ensure that switching tabs, reloading page or refreshing it won't make this happen? Or is this what is actually supposed to be happening?
Have you looked at saving it in as session data? Im not to familiar how Angular state works, but when you set original state you can look for the session key "authorized" and if it doesnt exist set auth to false, if it exists set it to the value.
localstorage.getItem(item)
and
localstorage.setItem(item)
There is also the option of making a component that handles the google auth and sends it to the state.
From the library documentation for vue-google-oauth page you linked it says you need to send that code back to your backend server to create a token to stay signed in, so it's behaving as expected. From here (https://www.npmjs.com/package/vue-google-oauth2#usage---getting-authorization-code) it states :
The authCode that is being returned is the one-time code that you can
send to your backend server, so that the server can exchange for its
own access_token and refresh_token
In other words, you need to do something with that code to make it persist in your app, otherwise it's just a one-time code, so looks to be expected.

ReactJS - how to setup login pattern?

I'm sorry if this question is a bit vague, but I'm tackling this problem for the first time and any pointer would be useful.
I am building a web app using ReactJS and I need a login system - first page with two fields username / password and submit button. The server returns a token (1234) and this needs to be used in an auth header (Authorization: Bearer 1234) in order to access the protected area.
How should I handle the login and make the browser update itself with the new content available after login?
As the others have pointed out, it is a good idea to use React-Router.
I think you can use pattern like this: You get user inputs and send them via AJAX (with JQuery, Superagent, whatever you want). If the input is valid and user authenticated, the server sends back token with some user info, which can include his roles or permissions. Based on these received data, you can use React-Router to render other component, e.g. welcome page (by calling replaceState on React-Router history object - in flux action for example).
Additionally, you should save this token in a cookie or into a session/local storage (in order to be able to use it on every subsequent request), and the user info could be stored in a Flux store. After saving this user the store emits change event, which should lead to rerender of your root component with the user information you got.
Then, based on the new user roles or permissions in your store, you can have for example ES7 decorator on some of your components deciding, if it displays the actual component or not.
Hope it helps you a bit.

How to return to Iron Router route after login when login is clicked and a different route?

In my app a user can navigate around anonymously without logging in. There is a dropdown to log in from any anonymous-friendly route. The dropdown has a link to a separate loginPage route and thus changes the route when clicked using Render.go('loginPage'). I'm trying to figure out how to return the user to the previous page they were on after logging in.
I understand the typical onBeforeAction(requireLogin)... method and that works if a page requires a login to access it. It re-evaluates Meteor.user() and then calls this.next().
My issue is when a user clicks to log in and they're taken to the loginPage route, how to then get them back to the previous page. I was trying to call something like Router.render('loginPage') in the click event but you can't call Router.render() on the client like how you can inside a route. Apparently only Router.go() works on the client, thus changing the route.
The only way I can think of is to have every anonymous-friendly route in my app have an onBeforeAction that tests for a Session variable (e.g. loginRequested). If the user clicks on "Sign In", it sets loginRequested which would invalidate the route. Once they sign in I would clear loginRequested and then the onBeforeAction would call this.next() taking them back to the previous page. This would work unless the user hits "Back" in their browser. I would have to listen for that and clear loginRequested so the route would validate. Is there a way to do that in Iron Router?
This just seems really hacky. Is there a better way to do this?
EDIT: I forgot to mention that my loginPage route actually has its own action: if the user goes directly to the login page through the URL it will forward them to a specific route.
Just call history.back(); after a successful log in.
E.g:
Router.route('/login', {
onBeforeAction: function(){
// Do logging stuff
history.back();
}
});
Iron Router is kind of hacky itself, so if you decide to handle logging in the route, you might have to call this.next() somewhere.
So it turns out the best way to solve my above problem is indeed through the use of Session variables. Something like:
if(!Meteor.user()) {
if(Session.get('wantsToLogIn`) == null)
this.next();
else
this.render('loginPage');
}
else
this.next();
So if a user is on some page and decides to log in, you just set a Session variable wantsToLogin. If you set it, it invalidates the onBeforeAction and evaluates to call this.render('loginPage'), once the user logs in the onBeforeAction again invalidates and listens for Meteor.user(), and as soon as the user is logged in the onBeforeAction calls this.next(). Basically everything I said in my question... I don't know why I didn't just do that to begin with.

Backbone js prevent url hash change when back/forward

I am working on a very basic SPA using Backbone.js. My app has few routes. Among them there are 2 that give me issues: the index route ("/#index") and menu route ("/#mainmenu").
A simple workflow in my app is as follows: the user fills a form -> clicks to login -> trigger ajax request -> if login successful go to "/#mainmenu" route. if login failed, remain on "/#index" route.
On "/#mainmenu" if the user clicks on logout -> ajax request -> if logout success go to "/#index". if logout failed remain on "/#mainmenu".
The issues that I am struggling with are:
A clean way to trigger transition to "/#mainmenu" after successful login (I currently use router.navigate("mainmenu", {trigger: true}); but read that should avoid using this approach, in derrick bailey's article https://lostechies.com/derickbailey/2011/08/28/dont-execute-a-backbone-js-route-handler-from-your-code/ )
A clean way to prevent the user to go back to the "/#index" when pressing Back button in the browser from "/#mainmenu" route. I will also would like to preserve the url hash to reflect the current view.
Prevent the user to go forward to "/#mainmenu" after successful logout.
Is that even possible to prevent url hash change when clicking browsers back/forward buttons?
When I say "clean" I refer to "what are the best practices?". I partially solved some issues by saving url hashes and restore the appropriate hash (by router.navigate(currentRoute, {replace: true}); ) but I feel that it's a hacky approach.
Any feedback is welcome and much appreciated.
One way to solve this problem is by applying an async before filter on the routes that require an auth status check before the actual callback route is executed.
For example:
https://github.com/fantactuka/backbone-route-filter
The philosophy of avoiding {trigger: true} is based on the fact that when the router gets triggered with this flag, the entire initialization procedure for that route gets triggered. You will lose the benefit of having previously defined appstates because the app will have to re-initialize all content while this work had alrady been done before.
In practice, I think that it is useful to assess what your web app actually does. If losing appstate isn't an issue because the views you want to render are entirely new, then I don't see a problem with creating a client side redirect that re-inintializes your app.
If, on the other hand, your app has many views already rendered for which you want to maintain the same state as before, you can listen for an auth state event on each component that requires it, and make only those views re-render accordingly if they need to.
I don't think there's anything wrong with triggering routes, have been doing this without any issue for 2+ years. It all boils down to your requirements, read the article looks like a lot of work to me.
There are multiple ways to do this. First, you can disable back/forward buttons using window.history.forward(). Second, my favourite, is to do the processing in Router#execute. A sample might look like :
execute: function(callback, args, name) {
if (!loggedIn) {
goToLogin();
return false; //the privileged route won't trigger
}
if (callback) callback.apply(this, args);
}

Why the conflicting variables?

I'm getting conflicting results between the facebook javascript SDK and the python requesthandler variables. The Javascript SDK says my user is not logged in, which is correct, while my template variable that comes from the base request handler says that my user is logged in and displays the name of the user. Is there enough info to tell what is wrong or should I paste the code I think is relevant here? A link to the login page that has the error is here. The example I used is called the runwithfriends demo app from facebook and everything with that app worked except using the logic from the app just from a website without requiring the user to be in the iframe of the app.
Plus I can't seem to get the real-time API working. I can only save userID and not refresh user data - why? I have the code but I'm not sure what's most relevant but here's some of the request handler, the relevant code is basically exactly the same as the one from the demo app:
def render(self, name, **data):
logging.debug('render')
"""Render a template"""
if not data:
logging.debug('no data')
data = {}
data[u'js_conf'] = json.dumps({
u'appId': facebookconf.FACEBOOK_APP_ID,
u'canvasName': facebookconf.FACEBOOK_CANVAS_NAME,
u'userIdOnServer': self.user.id if self.user else None,
})
data[u'logged_in_user'] = self.user #variable that is the problem
data[u'message'] = self.get_message()
data[u'csrf_token'] = self.csrf_token
data[u'canvas_name'] = facebookconf.FACEBOOK_CANVAS_NAME
self.response.out.write(template.render(
os.path.join(
os.path.dirname(__file__), 'templates', name + '.html'),
data))
And even more strange, I can also get the application in a state where the javascript SDK says the user is logged in and the template variable logged_in_user says otherwise. Why are the variables conflicting?
Update: Here are screenshots from the strange login flow. I can go to my page and my name from facebook appears:
Then when I go to next page it also looks alright and has my name
But if I log out then I gets in impossible state: my name + logged out
How can I resolve this strange conflict between js and back-end?
Update: Since I only have this problem for one of my apps I can take what works from my other app and integrate. This page seems to work from my other app: http://cyberfaze.appspot.com/file/20985
Your 'user' is probably referring to the Django user not the Facebook user. Make sure you synchronize the two accounts correctly using a custom authentication backend. It's possible that the accounts get out of sync i.e. if the user switches browsers.
Keep in mind that the Facebook Python SDK will stop working after October 1st unless they update it to Oauth2.0 which is unlikely.
I just updated django-facebook-graph to work with the new authentication flow.

Categories