14
votes

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

2 Answers

15
votes

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

4
votes

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.