14

As Angular is SPA that's terrific, but what if I need some other page not related to index.html, how is realised by UI-Router states with different ui-views?

For example, I have index.html:

<!DOCTYPE html>
<html data-ng-app="npAdmin">
<head>
...
</head>
<body>
   <header>
      <data-user-profile class="user-profile"></data-user-profile>
  </header>

  <section class="content-wrapper">
      <aside data-main-menu></aside>
      <div class="main-content" data-ui-view></div>
  </section>

  <footer class="row"></footer>
...
</body>
</html>

app.js:

var app = angular.module('npAdmin', ['ui.router']);

app.config(['$httpProvider', '$stateProvider', '$urlRouterProvider', function($httpProvider, $stateProvider, $urlRouterProvider) {

    $stateProvider
    .state('dashboard', {
        url: '/dashboard',
        templateUrl: '/app/dashboard/dashboard.html',
        controller: 'DashboardCtrl'
    })
    .state('crm', {
        url: '/crm',
        templateUrl: '/app/crm/crm.html',
        controller: 'CrmCtrl'
    })
...

Now I need login.html which is totally different from index.html (don't need index's header, footer, sidebar) but config stateProvider only looks to index.html ui-view and changes content to it by states. How to combine login.html?

It seems not that hard, but I don't get it.

2 Answers 2

15

As you expected, it is not so difficult, there is a plunker.

The trick is to move the common stuff for all views inside of the specific template e.g. common.html and create the abstract state. Other words, the index.html will remain clean:

<body>

    <div ui-view=""></div>
</body>

And its previous content (content of the index.html) would be moved to common.html. The state definition could look like this:

$stateProvider
  .state('common', {
    templateUrl: 'tpl.common.html',
    abstract: true,
  })
  .state('dashboard', {
    url: '/dashboard',
    parent: 'common',
    ...
  })
  .state('crm', { 
    url: '/crm',
    parent: 'common',
    ...
  })
  .state('login', {
    url: '/login',
    templateUrl: 'tpl.login.html',
  });

$urlRouterProvider.otherwise('/crm');

What is interesting (I'd say) is that we introduced abstract state, without url. So the all current logic will remain, just the abstract will play role of a layout template.

Check more here: example

Sign up to request clarification or add additional context in comments.

5 Comments

Now I know how to use abstract state property. Thank you.
Great to see that;) ui-router is incredible and really powerful... Enjoy it ;)
@KillABug I would suggest, issue question. Show more details. You will surelly get an answer. Or let me know I can check it as well. Comment is not suitable for investigating why is your code not working... Does it make sense?
@KillABug If I will know, I will help. But your question will target more guys than must me, so you will get answer... I am sure
4

I also had this problem before, refer to THIS if you're interested. In that link, I also handled returnUrl and 401 http status code in case the user is not authorized.

In your case, I suggest you design your application like this:

index.html:

<!DOCTYPE html>
<html data-ng-app="npAdmin">
<head>
...
</head>
<body data-ui-view>

</body>
...
</html>

main.html:

  <header>
      <data-user-profile class="user-profile"></data-user-profile>
  </header>

  <section class="content-wrapper">
      <aside data-main-menu></aside>
      <div class="main-content" data-ui-view></div>
  </section>

  <footer class="row"></footer>

login.html

(include your html for this view)

App.js:

var app = angular.module('npAdmin', ['ui.router']);

app.config(['$httpProvider', '$stateProvider', '$urlRouterProvider', function($httpProvider, $stateProvider, $urlRouterProvider) {

    $stateProvider
    .state('login',{
       url:"/login",
       templateUrl: '/app/login.html',
       controller: 'LoginCtrl'
     })
    .state('main',function(){
       url:"/",
       templateUrl: '/app/main.html',
       controller: 'MainCtrl',
       abstract: true //you could use abstract state or not depending on your design 
    })
    .state('main.dashboard', { //inherit from your main
        url: '/dashboard',
        templateUrl: '/app/dashboard/dashboard.html',
        controller: 'DashboardCtrl'
    })
    .state('main.crm', { //inherit from your main
        url: '/crm',
        templateUrl: '/app/crm/crm.html',
        controller: 'CrmCtrl'
    })

Explanation:

As angular is SPA, your index.html should cover all views of your application. There are multiple ways to ensure that. In this example, the login is also a state in your application that is separated from your main. By utilizing state inheritance in angular router, you could further have child states in your main which are dashboard and crm in this case.

4 Comments

In addition to the above, if you're going to have a separate Login page make sure you implement an Authentication Check service. This way, if the user isn't logged in they'll be re-directed to the login page. See this video for a basic implementation.
@Ed B: Sure, because that's not included in the question. And we will check that for all requests, not only for login page.
Thanks a lot, very exhaustive answer but with some minor mistakes. Radim's solution with abstract state seems as perfect solution.
@swolfish: I did not test the code, I just gave the idea. And as I said, there are multiple ways to do that. It's just a matter of design.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.