angular-ui / ui-router

The de-facto solution to flexible routing with nested views in AngularJS
http://ui-router.github.io/
MIT License
13.53k stars 3k forks source link

How can I make angular ui-router work with html5mode=true automatically? #372

Closed henrytao-me closed 11 years ago

henrytao-me commented 11 years ago

Hi all! How can I make angular ui-router work with html5mode=true automatically? I mean:

In angular, you have the link like this href="#/abc". If you set html5mode=true, it automatically redirect to /abc when you click on link abc. If html5mode=false, it keeps #/abc. So, nothing need to change in your html code.

In angular ui-router, if you plan to enable html5mode=true, you need to change all link from html code to something like: (without #). If html5mode=false, you need to have # in url.

So, how to fix it in angular ui-router? Thanks for advice!

timkindberg commented 11 years ago

Use ui-srefdirective. Look at API reference.

henrytao-me commented 11 years ago

Hi! I found this https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref

Look good. But it doesn't work. I can not find any ui-sref directive in here http://angular-ui.github.io/ui-router/release/angular-ui-router.js

Thanks!

henrytao-me commented 11 years ago

OK! I found ui-sref in development version! Thanks!

henrytao-me commented 11 years ago

ui-sref doesn't fix this problem.

My problem above is not dynamic generate href. It is html5Mode combine with ui-router, automatically.

In ui-router:

In original angular router:

timkindberg commented 11 years ago

The point is that with uisref you don't specify href at all. The href is generated and will use # if html5mode is disabled. That's the only way we support both modes dynamically.

henrytao-me commented 11 years ago

I write a directive like this: to overcome this issue:

Usage: just put hash # in ehref Dashboard. ehref Directive will automatically check html5Mode enable or disable.

angular.module('directive.ehref', []).config(function($locationProvider){ this['directive.ehref'] = $locationProvider; }).directive('ehref', function(){ var config = this['directive.ehref']; return function($scope, $element, $attrs){ if(config.html5Mode() === true){ $element.context.href = $attrs.ehref.replace('#' + config.hashPrefix(), ''); return; }; $element.context.href = $attrs.ehref; }; });

henrytao-me commented 11 years ago

Hi Timkindberg!

Does uisref support hashPrefix when developer set on $locationProvider.hashPrefix('!')?

timkindberg commented 11 years ago

That I'm not sure of.

henrytao-me commented 11 years ago

I read the ui-router v0.0.2. I found this return !$locationProvider.html5Mode() && url ? "#" + url : url;

So I think it still doesn't support hashPrefix!

laurelnaiad commented 11 years ago

@henrytao-me, check out this SO answer. I'm using this solution and it works.

Your config function would look something like:

    function ($locationProvider, $provide, $stateProvider) {
      //comment out the decorator function for html5mode
      //uncomment the decorator function for forced hash(bang) mode
      // $provide.decorator('$sniffer', function($delegate) {
      //   $delegate.history = false;
      //   return $delegate;
      // });
      $locationProvider.html5Mode(true);

     // etc.
connor11528 commented 10 years ago

add this line to app.config:

$locationProvider.html5Mode(true).hashPrefix('!')

and include this line in the head of index.html:

<base href="/">

alanquigley commented 10 years ago

Incase the above fails and your using yeoman-angular try this: http://jjt.io/2013/11/16/angular-html5mode-using-yeoman-generator-angular/

zaphz commented 9 years ago

@jasonshark, Thank you for your answer.

RaviSankarRao commented 9 years ago

@jasonshark Thanks a lot for your answer. Adding worked to remove those ugly URLs. Was using html5Mode true and hasPrefix as !

connor11528 commented 9 years ago

:+1:

FurkanArslan commented 9 years ago

@jasonshark , thank you very much for your answer

mahesh5b5 commented 9 years ago

Hi I'm using html5 url mode to hide hash tag in my angular URL. If i refresh or copy/paste URL to other tab on browser its showing 404 error page not found

Please help me out

shardool commented 9 years ago

@mahesh5b5, minutes ago I bumped into the same issue and I realized that it is in fact the expected behavior and here's the explanation: When you tell the $locationProvider to use the html5 mode, the route URLs look as desired and work fine when you navigate to them by "clicking" the relevant links. example: you can navigate from http://myWebsite/home to http://myWebsite/about by clicking the anchor tag as this navigation is orchestrated by the angular-ui-router. However once you are on the destination URL http://myWebsite/about, refreshing it will cause the browser to make a fresh "get" request to that URL and is not orchestrated by the angular-ui-router. This fresh request should be served by the server "myWebSite". Hope this explanation helps :)

ldynia commented 9 years ago

@shardoo So if I will send somebody a link to http://myWebsite/home he/she will get 404, because a user did not enter myWebsite from the root location ("/"). Is there a fix for this behavior so angular will recognize request and will generate content?

isaiahgrey93 commented 9 years ago

This is because when you submit the link it makes a request to that route on the server, when angular is using client side routing. To enable html5 mode, you need to serve the index on all routes for html5 mode. Like this for a node app.

// This is a server file
app.get("*", function(req, res) {
    res.render("./index.html");
}

Angular UI router html5 mode works by say...

// This is in your app module config.
$locationProvider.html5Mode(true);
// This is in your index.html head.
<base href="/" />

This is all you need for the pretty urls essentially, the issue is if you navigate to a route with out the hash prefix and submit a link to the server, it will cause a server request for that route. So like I mentioned about you need to render the index on all routes submitted to the server.

ldynia commented 9 years ago

@isaiahgrey93 Thanks for your input. You are very right. I fixed this problem on the server. I render all my urls to index.html page. By doing that angular reads the url, and loads appropriate state. Regards ;)

smkamranqadri commented 8 years ago

i had deployed my client on firebase server so didn't make redirect all routes to index.html so what to do?

ldynia commented 8 years ago

Have you set in your apaceh/nginx virtualhost conf file html5 handling ? Here is my below set up

  ### serve index.html as django app
  <Directory /srv/www/compare/htdocs/core/frontend/templates>
    ## link: https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-configure-your-server-to-work-with-html5mode
    ## link: http://stackoverflow.com/questions/869092/how-to-enable-mod-rewrite-for-apache-2-2
    RewriteEngine on
    # Rewrite everything else to index.html to allow html5 state links
    # Don't rewrite files or directories
    #RewriteBase /
    RewriteCond %{REQUEST_FILENAME} -f [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^ - [L]
    RewriteRule ^ index.html [L]
  </Directory>
smkamranqadri commented 8 years ago

my app hosted on firebase not apaceh/ngix??

ldynia commented 8 years ago

Then I cannot help you. I heave no experience with firebase.

fantaJinMode commented 8 years ago

@shardool Any suggestion how you solved your problem ?. I am also having the same issue

IainCole commented 8 years ago

Does this not help? https://www.firebase.com/docs/hosting/guide/url-redirects-rewrites.html

deven003 commented 8 years ago

For those who are using Angular JS with Laravel 5 and facing page not found issue after page refresh while implementing @isaiahgrey93 solution, add following line in your route.

Route::any('{path?}', function()
{
    return File::get(public_path() . '/angular.html');
})->where("path", ".+");

source: http://stackoverflow.com/a/28683547/1099229

Mimicx commented 8 years ago

i'm working in a ionic application, how i can configure it from the server site?

mahesh5b5 commented 8 years ago

Thanks :+1:

RongBranovate commented 8 years ago

any idea how to make it work with codeigniter?

cullsin commented 8 years ago

Hi,

Seems like page refresh not working in my url "http://anaoh.com/about" with enabled html5 mode.

Can you please suggest me what I am missing.

Raja K

RongBranovate commented 8 years ago

@cullsin, you need to set on you your server routing that all pages will go to the home page(you default one).

Also, tell us what you are using on the server side(framework or language).

P.S - If any one is using Codeigniter 3 this is my solution.

cullsin commented 8 years ago

Hi,

I am using Phalcon REST Framework in the backend so it serves only data. I have configured apache Rewrite Engine too.

   <IfModule mod_rewrite.c>
    RewriteEngine On
    # Don't rewrite files or directories
    RewriteCond %{REQUEST_FILENAME} -f [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^ - [L]

    # Rewrite everything else to index.html to allow html5 state links
    RewriteRule ^ /index.html [L]
    </IfModule>
cullsin commented 8 years ago

Hi,

This is working greate. I had a code issue in the loading. Sorry for the confusion.

Raja K

jetsgit commented 8 years ago

This solution is working for Rails 4.x.x and AngularJS 1.5.7.

app.coffee

angular.module('myApp').config( ($stateProvider, $urlRouteProvider, $locationProvider)  ->
  $stateProvider.state()  # Your states here
  $locationProvider.html5mode true

application.html.erb:

<head>
  <title>My Wonderful World</title>
  <base href="/">

routes.rb:

root 'home#angular'
get '*path' => 'home#angular'

home_controller.rb:

class HomeController < ApplicationController
  def angular
    render 'layouts/application'
  end
end

An alternate approach:

application_controller.rb:

class ApplicationController < ActionController::Base
  ...
  def index
end

routes.rb

root 'application#index'
get '*path' => 'application#index'
DustinJSilk commented 8 years ago

My issue was that my base url looked like this: <base href="/">

So had to add a / to my first state url: $stateProvider .state('index', { url: "/", ...

ashwinigawade007 commented 8 years ago

Refer this http://oneplaceworld.blogspot.in/2016/09/pretty-urls-in-angularjs-removing-Hashtag.html

severus-ebay commented 8 years ago

I am having a problem with the HTML5 and ui.router If I activate the HTML5 like: $locationProvider.html5Mode(true); my URLs looks perfect (without #!) but then if I refresh the page, its gets blank.

If I deactivate the HTML5 (just out comment: // $locationProvider.html5Mode(true);) I can refresh and I do not lose the page, but I have the ugly URL like: http://localhost:50895/#!/addcontact

I added the following rewrite method in my Web.config (I am in ASP.NET) but it crash the application:

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

Any idea?

macsermkiat commented 8 years ago

I'm having this problem too. Cannot refresh page with html5Mode(true) I use Express serving index file like

    app.all('/*', function(req, res, next) {
    res.sendFile('index.html', { root: __dirname });
    console.log("send index");
    });

but there was no luck.

jetsgit commented 8 years ago

Did you follow steps I outlined above, including:

root 'your_controller#your_method'
get '*path' => 'your_controller#your_method'

in routes.rb ?

macsermkiat commented 8 years ago

No. Actually I use Node and Express, not Rails.

smanners commented 8 years ago

have you tried

$locationProvider.html5Mode({
        enabled: true,
...
    }).hashPrefix('!');
macsermkiat commented 8 years ago

Yes. I have hashPrefix('!') for sake of SEO. was try to change to res.sendFile(path.join(__dirname + 'index.html')); or + '/app_client/index.html' still no good.

This was my static file serve on upper line. app.use(serveStatic(path.join(__dirname, 'public'))); app.use(serveStatic(path.join(__dirname, 'node_modules'))); app.use(serveStatic(path.join(__dirname, 'app_client')));

hmtri1011 commented 8 years ago

I have same problem with macsermkiat. I'm using MEAN Stack, Node for back-end and Angular JS for front-end. I'm also use : if(window.history && window.history.pushState) { $locationProvider.html5Mode({ enabled : true, requireBase : false }).hashPrefix('!'); in my app.route.js and base href="/" in my home.html. It can remove the hash # but when i try reload i get an error can get/state-name ... Any solution for this ?? thanks for your help }

hmtri1011 commented 8 years ago

After 4 hours !! Problem Solve :D

macsermkiat commented 8 years ago

How?

hmtri1011 commented 8 years ago

Back-end : In your app.js : app.get('/any-thing-you-want/*', function (req, res) { res.sendFile(path.join(__dirname, './views', 'home.html')); // change this });

Front-end : In your home.html ( or index.html ) add this line base href="/any-thing-you-want" (same string with your app.js) In app.route.js $urlRouterProvider.otherwise('/any-thing-you-want/'); .state('app') url : '/any-thing-you-want/' ...... ......;

              if(window.history && window.history.pushState) {
        $locationProvider.html5Mode({
            enabled : true,
            requireBase : false
        }).hashPrefix('');
    }

done.... change ui-sref or href in front-end from #/... to any-thing-you-want/..... or just use $state.go(...) Sry for my bad English..

waqas-syed commented 7 years ago

@severus-ebay : This configuration works for me when I deploy the application on IIS. It doesn't work(reason I don't know) when I run this application from Visual Studio.

Also, you can try replacing <action type="Rewrite" url="/index.html" /> with <action type="Rewrite" url="/" />

You can also check the answer for this question and try this configuration, may be it will help: https://stackoverflow.com/questions/27749776/angularjs-with-html5modetrue-on-iis-and-default-document

abhiramgiri commented 6 years ago

Hi index.html `<!DOCTYPE html>

Example :
` **home.html** `Hi This is HOME PAGE` **module.html** `Hi This is MODULE PAGE` **app.js** `var app = angular.module('app',['ui.router']); app.config(function ($stateProvider, $urlRouterProvider,$locationProvider) { $urlRouterProvider.when("", "/"); $stateProvider .state("/", { url: "/", templateUrl: "home.html" }) .state("/module", { url: "/module", templateUrl: "module.html" }); $locationProvider.html5Mode(true); $locationProvider.hashPrefix(''); });` If url is _localhost/Example/_ Its opening home page fine But if url is _localhost/Example/module_ its showing 404 Not found. Please help. >