1

I'm trying to edit a project so that it uses a root view/state, which holds all the other views/states inside it. Before, every page was it's own independent state which wasn't that great when I wanted to add something globally to all states as it would mean you'd have to use $rootScope too often.

So in app.js I've done this:

$stateProvider
  .state('app', {
    url: '/',
    templateUrl: 'app/app.html',
    controller: function($state) {
      $state.go('app.home');
    }
});

So my logic here is that I want to keep the same structure of the website and everything like that. So inside app.html I have just included <div ui-view></div> so that I can inject all the child states, and then on load I am just loading the home state which was originally just the homepage called on '/'.

So now, app.homeis this:

$stateProvider
  .state('app.home', {
    templateUrl: 'app/home/home.html',
    controller: 'HomeCtrl'
  });

No URL here as I'm just loading it from app anyway. And here is another page I've tested:

$stateProvider
  .state('app.test', {
    url: '/test',
    templateUrl: 'app/test/test.html',
    controller: 'TestCtrl',
    authenticate: true
  });

The routing works fine, and the views are loaded, but there are a couple of issues.

  1. When navigating to /test, the URL will actually be http://localhost:4000//test with two slashes. I can force it to be one slash if I make the url just test in the stateProvider, but I don't think that's the correct solution.

  2. If I reload the page from /test it will also just redirect me back to http://localhost:4000/ and the root state.

Any ideas?

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
germainelol
  • 3,231
  • 15
  • 46
  • 82
  • Did you try to define empty url on the state app `url: '',` and configure `$urlRouterProvider.otherwise('app.home')`? This way slash won't be added to child views and `/` route will be handled as well. – Dmitry Evseev Oct 31 '15 at 07:12

1 Answers1

1

The url is built from all parents url definitions - plus current state's url. I.e.:

"\" + "\test" === "\\test"

In case, we want to have url without parent part, we can use this sign ^:

$stateProvider
  .state('app.test', {
    url: '^/test',
    templateUrl: 'app/test/test.html',
    controller: 'TestCtrl',
    authenticate: true
  });

Absolute Routes (^)

If you want to have absolute url matching, then you need to prefix your url string with a special symbol '^'.

$stateProvider
  .state('contacts', {
     url: '/contacts',
     ...
  })
  .state('contacts.list', {
     url: '^/list',
     ...
  });

So the routes would become:

  • 'contacts' state matches "/contacts"
  • 'contacts.list' state matches "/list". The urls were not combined because ^ was used.

So, going to '\test' without absolute routes (^) will in fact trigger the otherwise setting, and go to default state...

EXTEND: how to create default state UI-Router standard way - working plunker

    .state('app', {
      url: '/',
      templateUrl: 'tpl.html',
      abstract: true,
      //controller:  function($state) {
      //  $state.go('app.home');
      //}
    })
    .state('app.home', {
      url: "",
      ...
    })
    .state('app.test', {
      url: '^/test',
      ...
    })  

check it here

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • I tried using `^/test` instead and that works for that route, but problem number 2 still occurs where if I refresh the page, then it actually loads `/` instead. – germainelol Oct 31 '15 at 06:31
  • Yep I'm using html5Mode – germainelol Oct 31 '15 at 06:32
  • Then you've configured your server wrongly. You should be sure, that server is ready for handling these url requests... check it here https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-configure-your-server-to-work-with-html5mode – Radim Köhler Oct 31 '15 at 06:34
  • It worked before when I had separate routes for `/main`, `/test` and `/some-route`. Only since applying these changes has it occurred? – germainelol Oct 31 '15 at 06:34
  • I'm actually using `grunt serve` as the server, so I will have to look at how to deal with an Express server from within grunt. – germainelol Oct 31 '15 at 06:35
  • It worked.. maybe. Hard to say, without any other information. But you for sure know - it is not UI-Router issue. It is related to your server. If you for a while turn of html 5 and use the ^ - you should confirm to yourself that client side is ok. And that will give you proof - server is an issue – Radim Köhler Oct 31 '15 at 06:36
  • Not sure what you mean. If I turn off html5 and refresh the page, it will still redirect me to the root url. I will look into fixing it on the server side of things though! – germainelol Oct 31 '15 at 06:40
  • I'm actually using the `angular-fullstack` generator, so it should come with the server settings out of the box. I'm thinking there is something wrong with my code seeing as it worked before I nested everything under the `app` state. – germainelol Oct 31 '15 at 06:57
  • I would suggest to adjust your state def, as I showed in my extended answer. There is also working plunker. ... and in case, that you would really need to have app as non abstract - use this approach http://stackoverflow.com/q/29491079/1679310 – Radim Köhler Oct 31 '15 at 07:05
  • Why not just make your app url to be ""? – Shikloshi Oct 31 '15 at 07:06
  • @Shikloshi check this https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-set-up-a-defaultindex-child-state – Radim Köhler Oct 31 '15 at 07:07
  • Thanks, the redirectTo solution actually worked for me perfectly! – germainelol Oct 31 '15 at 07:20
  • I would say that this is really far the best way how to introduce defaults.. good luck with UI-Router ;) – Radim Köhler Oct 31 '15 at 07:22
  • @RadimKöhler .. Thanks Radim, great stuff and a lot of clarifications for me. – Shikloshi Oct 31 '15 at 07:30