meyousikmann
meyousikmann

Reputation: 861

Routing and navigation in Angular 2

I am going through the tutorials for Angular 2 and have been able to get a simple application up and running. Now, I am moving on to the routing and navigation part found here https://angular.io/docs/ts/latest/guide/router.html, but something isn't working for me.

I went to the live example in Plunker and downloaded the code from there. I then setup a solution in Visual Studio 2015 and plugged in all of the code from the Plunker download. The application works perfectly except for one thing, the navigation doesn't seem to work as the documentation would seem to indicate.

I start debugging the application in Visual Studio using IIS Express and Chrome browser. The main page loads correctly and I can click on the links for Crisis Center and Heroes. When I click the links, the component views correctly load and everything looks perfect.

Now, if I try to navigate by simply typing in the URL, the component views don't load and all I have is a blank page.

For example, I start debugging the application in Visual Studio and the Chrome Browser opens with the URL http://localhost:56074/. The main page is loaded correctly with the "Component Router" header and the two links for "Crisis Center" and "Heroes". Now, if I simply go to the address bar and add "/crisis-center" to the end of the URL so it looks like http://localhost:56074/crisis-center, I get a blank page. The Chrome console shows the following error:

GET http://localhost:56074/crisis-center 404 (Not Found) Navigated to http://localhost:56074/crisis-center

and the Network trace clearly shows a 404 for crisis-center. In fact, if I use the navigation link on the main page for Crisis Center and click on it to show the crisis center component view, and then simply hit the refresh button to refresh the page while at the crisis center view, the same result happens.

Is this a Visual Studio issue? IIS Express? Other ideas?

We are a .Net development shop and our primary development environment is Visual Studio. If this is an issue with developing an Angular 2 application in Visual Studio using IIS Express, this may be a show stopper.

If anyone wants to try the same thing I can zip up my VS solution and share.

Anyone tried an Angular 2 application in Visual Studio using IIS Express that can maybe tell me what I am doing wrong?

Upvotes: 10

Views: 11952

Answers (6)

ferralucho
ferralucho

Reputation: 657

You can fix the error by implementing hash location strategy:

To enable HashLocationStrategy it's like this:

RouterModule.forRoot(routes, {useHash: true})

URL can contain some data prepended with a # character.

The # part of the URL is called the hash fragment. It’s never sent to the server,

example: http://example.com/#/clients

Upvotes: 1

Steve G
Steve G

Reputation: 13357

Old question, but I wanted to provide this suggestion as an alternative for future readers as I preferred the Rewrite method:

Building upon the answers from stas.ivash and Adrian Moisa: I used their URL Rewrite suggestions, but instead of listing out routes, I modified the regex to route everything excluding the files that our Angular 2 CLI generated app needs, with the given extensions (.bundle.js, .bundle.map, etc...):

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="AngularJS" stopProcessing="true">
          <match url="^(?!.*(.bundle.js|.bundle.map|.bundle.js.gz|.bundle.css|.bundle.css.gz|.png|.jpg|.ico)).*$" />
          <conditions logicalGrouping="MatchAll">
          </conditions>
          <action type="Rewrite" url="/"  appendQueryString="true" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

I can't really speak to the performance implications of using this RegEx solution in a Production environment, but it works well for us on our Dev and Stage environments.

Upvotes: 1

tergd1
tergd1

Reputation: 558

Angular 2 by default uses HTML5 routing, you either have to map all server requests to index.html by adding the following to web.config

<rewrite>
    <rules>
        <rule name="redirect all" stopProcessing="true">
            <match url="^(.*)$" ignoreCase="false" />
            <conditions logicalGrouping="MatchAll">
                <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" pattern="" ignoreCase="false" />
            </conditions>
            <action type="Rewrite" url="PATH TO INDEX.HTML" appendQueryString="true" />
        </rule>
    </rules>
</rewrite>

or implement the HashLocationStrategy, as described in angular docs here

provide(LocationStrategy, {useClass: HashLocationStrategy})

Upvotes: 21

G Chen
G Chen

Reputation: 199

This is my solution: https://csjdpw.atlassian.net/wiki/display/~Genhan.Chen/404+issue+for+Angular+2+routing

Refers to another posting: AngularJS 2 routing

Upvotes: 0

Adrian Moisa
Adrian Moisa

Reputation: 4343

In addition to @stasivash answer: If you have trouble making ajax requests to a certain path in your project, such as YOUR-DOMAIN/api/..., I suggest adding the following condition:

<add input="{REQUEST_URI}" negate="true" pattern="^\/api\/.*$" ignoreCase="true" />

resulting in:

<rewrite>
  <rules>
      <rule name="redirect all" stopProcessing="true">
          <match url="^(.*)$" ignoreCase="false" />
          <conditions logicalGrouping="MatchAll">
              <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" pattern="" ignoreCase="false" />
              <add input="{REQUEST_URI}" negate="true" pattern="^\/api\/.*$" ignoreCase="true" />
          </conditions>
          <action type="Rewrite" url="/index.html" appendQueryString="true" />
      </rule>
  </rules>
</rewrite>

Upvotes: 3

Bharathi Mohan
Bharathi Mohan

Reputation: 56

For this issue, you need to use PathLocationStrategy or HashLocationStrategy for your application. It's available in the 'angular2/router'.

Example for using HashLocationStrategy:

boot.ts

bootstrap(AppCmp, [
       ROUTER_PROVIDERS,
       provide(LocationStrategy, {useClass: HashLocationStrategy})
   ]);

and in your main component,

class AppCmp {
          constructor(location: Location) {
          location.go(location.path());
       }

The location.path() dynamically gives the path for the page to be loaded.

Upvotes: 2

Related Questions