LatentDenis
LatentDenis

Reputation: 2991

AngularJS: UI-Router solving routing hash-bang didn't work

I am currently using Angular version 1.6.4.

To solve the hashbang issue I was having, where all of my URL's were in this format:

http://localhost:8885/#/hotels/holiday-inn

My app.js including the router (using ui-router):

$urlRouterProvider.otherwise('/');
$locationProvider.hashPrefix('');
$locationProvider.html5Mode(true);

$stateProvider
    .state('index', {
        url: '/',
        templateUrl: 'index.html',
        controller: 'hotelController'
    })
    .state('login', {
        url: '/hotel/:name',
        templateUrl: 'views/hotel.html',
        controller: 'hotelController'
    });

My ui-view is located in Index.cshtml (I've previously had everything in _Layout.cshtml but moved everything to Index.cshtml):

<!DOCTYPE html>
<html ng-app="hotelScheduler">
<head>
    <meta charset="utf-8" />
    <base href="/">
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My Application</title>
    <link href="~/css/bootstrap.min.css" rel="stylesheet" />
    <script src="~/lib/angular/angular.min.js"></script>
    <script src="~/lib/angular-ui-router/release/angular-ui-router.min.js"></script>
    <script src="~/js/app.js"></script>
    <script src="~/js/hotelController.js"></script>
</head>
<body>
    <div ui-view>
    </div>
</body>
</html>

Now I'm having a different problem. If I access http://localhost:8885/hotel/holiday-inn, I get a 404.

Why is this happening?

Additional troubleshooting:

If I access http://localhost:8885/#/hotel/, it shows index.html rather than views/hotel.html and changes the address to http://localhost:8885/#%2Fhotel%2F. (I understand this is the work of otherwise in the routing, but why does it work with a URL with which starts a hashbang?)

I've been asking around and looking online and people suggest the rest is done through C#'s MapRoute or Server Side Code.

How would I do this via either option? If I were to do this Server Side, how do I do this via ASP.Net Core and Visual Studio?

Here's my current MapRoute:

app.UseMvc(config =>
{
    config.MapRoute(
        name: "Default",
        template: "{controller}/{action}/{id?}",
        defaults: new { controller = "App", action = "Index" }
    );
});

ANOTHER EDIT: Based on commented suggestions and https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-configure-your-server-to-work-with-html5mode, I've tried adding this code to my web.config for a server rewrite:

<system.webServer>
  <rewrite>
    <rules> 
      <rule name="Main Rule" stopProcessing="true">
        <match url=".*" />
        <conditions logicalGrouping="MatchAll">
          <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
          <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
        </conditions>
        <action type="Rewrite" url="/" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>

But now, absolutely everything just redirects to the root/home page: localhost:8885/.

Any help?

Upvotes: 3

Views: 1462

Answers (2)

Srikanth B
Srikanth B

Reputation: 143

I was facing similar issue with AngulaJS SPA, I could resolve with the following code:

Startup.cs

app.Use(async (context, next) =>
            {
                await next();
                if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value))
                {
                    context.Request.Path = "/index.html";
                    await next();
                }
            })
            .UseDefaultFiles(new DefaultFilesOptions { DefaultFileNames = new List<string> { "index.html" } })
            .UseStaticFiles()
            .UseMvc();

Index.html

<base href="/" />

and while referencing static files under wwwroot folder use a forward slash

<script src="/app.js"></script>
<script src="/app/services/auth.service.js"></script>

app.js

$stateProvider
        .state('home', {
            url: '/',
            templateUrl: '/index.html',
            controller: 'HomeController',
            controllerAs: "vm"
        });

$locationProvider.html5Mode({
        enabled: true,
        requireBase: true
    });

$urlRouterProvider.otherwise('/stores');

url rewrite in web.config does not work anymore with latest ASP.NET core, you can remove that code from web.config.

if you are using MVC, you can try with the following code, though I haven't

        app.UseStaticFiles()
           .UseMvc(routes =>
           {
               routes.MapRoute(
                   name: "default",
                   template: "{controller=Home}/{action=Index}");
               routes.MapSpaFallbackRoute("spa-fallback", new { controller = "Home", action = "Index" });
           });

Upvotes: 1

couzzi
couzzi

Reputation: 6366

$location in HTML5 mode requires a <base> tag to be present.

via the docs:

If you configure $location to use html5Mode (history.pushState), you need to specify the base URL for the application with a tag or configure $locationProvider to not require a base tag by passing a definition object with requireBase:false to $locationProvider.html5Mode():

https://docs.angularjs.org/error/$location/nobase

The fix is to update your $locationProvider code to this:

 $locationProvider.html5Mode({
     enabled: true,
     requireBase: true
 });

And then, inside of your <head>, set your <base> accordingly. The most common pattern is /, but your application might requires assets to be accessed from a different folder.

<head>
  <base href="/">
  ...
</head>

Or, if you want to be clever, like https://plnkr.co does for bootstrapping Angular plunks:

<head>
  <script>document.write('<base href="' + document.location + '" />');</script>
</head>

Upvotes: 1

Related Questions