Creating a login for my SPA checking that my approach is not stupid

119 views
Skip to first unread message

Stephen Adams

unread,
May 21, 2014, 12:08:16 PM5/21/14
to ang...@googlegroups.com
Hi,

I'm working on first big AngularJS project and one of the first tasks I'm tackling is creating the login mechanism. The way I want the page to work is, when the user is logged out they see the main login screen, once they have successfully logged in the main template shows the full application UI (header, navigation etc).

So far I have created all my pages to load through ngView, but when I load the loginView I still have all the UI components in the main template (navigation etc). My plan was to create a login service that, for now, just checks that the user has submitted the login details. Then is sets a property of 'loggedIn'. 

I was then going to use this loggedIn property to check against in each UI element, so if loggedIn == true the ng-show will display the UI element if not the the UI element is hidden.

The main problem I'm trying to tackle is have one main template and loading the login as a view within that template. Ideally I'd have two templates, one for the loggin and one for the main template. 

Any suggestions on the approach I'm taking?

Thanks

Stephen

Eric Eslinger

unread,
May 21, 2014, 12:57:59 PM5/21/14
to ang...@googlegroups.com
I'm using ui-router to accomplish this. Basically, I created a top-level template in my index.html (equivalent) file that includes a header, footer and body ui-view element. Then in all my routes, I have templates shoved in there for app-header.html, etc.

I have a special loginrequired route that loads different header/footer templates (which make use of no logged-in information like username). Then, when I detect that the user's not logged in, I just issue a $state.go 'loginrequired'. I do this in several situations: when the user's cookie is unset and when any of my $http calls return 401. That's because my login process generates a bearer token that I stash in a cookie, so either there's nothing there to start, or the bearer token has expired and the user has to log in again.

That loginrequired page handles the login stuff ("click here to open a google oauth session in a new tab", more-or-less).

UI Router makes this a lot easier, but you can do it with ngRouter as well IIRC. I definitely suggest you separate your views into logged-in and not-loggedin templates unless they're complex and share a lot. In that case, that feels like a definite use for ui-router and multiple named views.

e


--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular.
For more options, visit https://groups.google.com/d/optout.

Stephen Adams

unread,
May 23, 2014, 7:10:55 AM5/23/14
to ang...@googlegroups.com
Hi,

I've just got ui-router set up and I'm going to give the solution you suggested a try. Does this mean that your stateProvider has a lot of duplicate entries for all the ui-view elements? Are you including them for each state?

Stephen

steven smock

unread,
May 23, 2014, 7:53:29 AM5/23/14
to ang...@googlegroups.com
Stephen,

Here is what worked best for me.

Because functionality on the login page is radically different from functionality in my SPA views, I opted to just use different pages entirely for login, registration, etc.  I know this is sort of a non-answer, but it eschewed a lot of complexity in my module setup.  Also, those pages are very small, so SPA's benefits are, to some degree, lessened anyway.

This approach made even more sense in my case, because a great deal of the site's functionality depended on a "User" object -- which contained permission flags for different views and actions, among other things -- which would not be available without an active session.

Best,
SS


Stephen Adams

unread,
May 23, 2014, 7:55:29 AM5/23/14
to ang...@googlegroups.com
That sounds interesting. How did you load the completely different pages? 

steven smock

unread,
May 23, 2014, 8:07:42 AM5/23/14
to ang...@googlegroups.com
In my case, I'm leaning on ASP.NET MVC, so it handles all of my of server-side routing.  

But speaking generally, our web server just provides them the old-fashioned way.  My login page is the default for my site -- really, just a form with some validation and AJAX calls behind it.  It uses an angular module, but it's very simple, and does not include any routing of its own.  The other non-spa pages are similar.


--
You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/9YAkivmip3A/unsubscribe.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.

Eric Eslinger

unread,
May 23, 2014, 1:31:41 PM5/23/14
to ang...@googlegroups.com
Long post ahead. Egghead.io has some good tutorials on ui-router and named views that I found really helpful (although I think the named-views one is pro-only, although-although a pro subscription to egghead.io has been a great investment for me at least).

What I did was define sub-routes in $stateManager. So my index.html has header, app and footer named views.

Here's my main routing:

angular.module 'clientApp.app', ['ng', 'ui.router']
.config ($stateProvider, $urlRouterProvider) ->
  $stateProvider.state 'app',
    abstract: true
    views:
      footer:
        templateUrl: 'app/app-footer.html'
      header:
        templateUrl: 'app/app-header.html'
   $urlRouterProvider.otherwise '/start'

(note that abstract is true and the 'app' ui-view has nothing in it).

Then here's my communities routing:

  $stateProvider.state 'app.communities',
    url: '/communities'
    views:
      'app@':
        templateUrl: 'components/app-templates/wide-right.html'
      'le...@app.communities':
        templateUrl: 'app/communities/communities-all-left.html'
      'ri...@app.communities':
        templateUrl: 'app/communities/communities-all-right.html'

I have a wide-right and a three-column app template, both are pretty simple html files with appropriately-named view (left and right, or left, middle and right) that contain the relevant responsive grid stuff to lay out prettily. Note that I did not have to set header@ or footer@, as this state app.communities is a substate of app, and therefore inherits the top-level app routing for views it doesn't override.

Below is a subroute for looking at a particular community. In this case I'm re-overriding the app@ template, albeit with the same template. That's because this *used* to have the three-column template, and I've not updated things yet to be more simple. But I'm routing specific new templates into the left and right views.

  $stateProvider.state 'app.communities.detail',
    url: '/:communityId'
    views:
      'app@':
        templateUrl: 'components/app-templates/wide-right.html'
      'le...@app.communities.detail':
        templateUrl: 'app/communities/communities-single-left.html'
      'ri...@app.communities.detail':
        templateUrl: 'app/communities/communities-single-right.html'

In this one, I'm overriding the right side view, but not the left side view (note the name there, ri...@app.communities.detal, that's where it was originally defined, you can easily make route-and-view naming mistakes here, or at least I've made plenty).

  $stateProvider.state 'app.communities.detail.conversations',
    url: '/conversations'
    views:
      'ri...@app.communities.detail':
        templateUrl: 'app/communities/communities-detail.html'

more of the same:

  $stateProvider.state 'app.communities.detail.conversations.detail',
    url: '/:docId'
    views:
      'ri...@app.communities.detail':
        templateUrl: 'app/communities/communities-detail-conversation.html'


So, my app's /communities/2/conversations/4 route displays conversation number 4 in the communities-detail-conversation template on the right side, information about community 2 in the left side of the screen, derived from the left@ communities-single-detail defined in app.communities.detail, and the same header and footer template defined way up at app.

Note that I deleted some other stuff from these layouts, notably the controller definitions.

The nice thing is that all my "pages" (communities, people, etc) can be defined as separate modules, instead of cluttering up a single /views folder somehwere. They add their routing info to the state manager at instantiation time. I can duplicate or not duplicate as necessary.

So I *also* have a login page thusly:

  $stateProvider.state 'login',
    url: '/login'
    views:
      header:
        templateUrl: 'app/login/login-header.html'
      footer:
        templateUrl: 'app/login/login-footer.html'
      app:
        templateUrl: 'app/login/login.html'

which overrides all the named views. None of these templates have any reliance on logged-in-user data. One could also have a signup route as well.





--
You received this message because you are subscribed to the Google Groups "AngularJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angular+u...@googlegroups.com.

Witold Szczerba

unread,
May 24, 2014, 6:24:02 AM5/24/14
to ang...@googlegroups.com

Hi guys,
I think you are extremely overcomplicating this all.
Check out the demo of my http-auth-module.... (focus on the showing login form mechanism). Can't write now, will continue within few hours.

Regards,
Witold Szczerba
---
Sent from my mobile phone.

--

Witold Szczerba

unread,
May 24, 2014, 7:28:57 AM5/24/14
to ang...@googlegroups.com
OK, I am back. Here's the demo app:
http://witoldsz.github.io/angular-http-auth/
The idea is: the SPA app has only one root template (the index.html).
The login form is there, ready to pop up any time. You just make it
invisible when it's not needed. On the other hand, we have everything
else: the application with menus, headers, footers, routes and whet
else. On the to of both of them is a simple directive which is
responsible for showing and hiding them when appropriate, so they are
never both visible at the same time.

The additional bonus of this solution is that you can implement the
resumable workflow, immune to losing of session, because showing the
login page DOES NOT change the state of scopes and controllers. Users
can be in the middle of something when they loose their sessions, the
login incident can happen and after it's all OK, they can continue
their job.

Regards,
Witold Szczerba
Reply all
Reply to author
Forward
0 new messages