7

I'm asking this because a couple of times now, I've tried to play around with the $locationProvider.html5Mode(true) command along with <base href="/"> and ran into a lot of errors calling the scripts/styles/images for my project. I guess there must be something I am doing wrong, but is there a certain folder structure you should follow so you don't run into these errors? Or is there a specific way that the base href works that I'm not quite understanding?

Recently, I thought I'd try it on a very, very small app. It's effectively a static website, but I want to take advantage of Angular's routing to make sure all of the pages can load instantly. So my structure would be something like this:

my-project
    css
    images
    js
        angular
            app.js
            app.routes.js
            mainCtrl.js
    views
        home.html
        about.html
        contact.html
    index.html

So I know that this folder structure isn't great, but I'll only be using Angular in this project for routing, nothing more, so it fits my needs.

I put into the head <base href="/">, put in body ng-app and ng-controller, and inside the body put a <div ng-view> somewhere too.

I added in the $locationProvider.html5Mode(true) and tried the app out. All of my scripts are then being loaded as http://localhost:8888/script.js which is incorrect. The project is located in a folder so that index.html is located in http://localhost:8888/my-project/index.html. So, it should be loading the scripts from http://localhost:8888/my-project/js/angular/app.js for example.

Is there something that I'm not understanding about the base href? Eventually I may host this app somewhere online, so I want the URLs to scripts etc to all be relevant to the file really. Anyone have any ideas?

Alright, so above the base href tag I would have my CSS styles which would be linked as css/style.css and at the bottom of my body tag I would have my scripts loaded as js/init.js or js/angular/app.js for example. This would try to load it as if the js folder is located directly at localhost:8888/js.

9
  • Sounds like you need <base href="/my-project/"> Commented Jul 7, 2015 at 2:03
  • 1
    base href is not just an angular call but also tells all your relative links where to start from. Where your js files are loaded from shouldn't have anything to do with your angular routing though. How are you loading them and where are you putting the base href? Commented Jul 7, 2015 at 2:03
  • Can you show an example of your index.html file, in particular the <script> tags Commented Jul 7, 2015 at 2:08
  • I updated my answer to show you @Phil. I understand that using that base href could work, but I thought that it should be making all files relative to this index file? Or is that not exactly how it will work? For example, if I was to put this app onto a server for the world to see, I would then have to change the `href="/my-project/" again. Commented Jul 7, 2015 at 2:46
  • @germainelol yup. The <base> tag sets the root path / URI to base all relative URIs from. If that path changes based on where it's deployed, you need to change it Commented Jul 7, 2015 at 2:56

1 Answer 1

10

The Angular framework is a Single Page Application (SPA) that is able to run in a browser by essentially tricking the browser into running code snippets rather than make server calls, by making use of the "hash" (#) page anchor. Normally, a URL with a # would jump to a specific anchor point in the page; in the case of Angular or other similar SPA frameworks, the # is redirected to a code segment instead.

Ideally, you would like to not have to reference this # in your page URLs. This is where Html5Mode comes into play. Html5Mode is able to hide the #, by using the HTML5 Push State (aka history API).

When Html5Mode is enabled, the normal links on the page are silently replaced by Angular with event listeners. When these events are triggered, the current page is pushed into the browser history, and the new page is loaded. This gives the illusion that you are navigating to a new page, and even allows for the back button to operate.

This is all fine when you are dealing with links which are clicked from within the running application, but relying on event listeners can't work if you navigate to the page from an external source, where Angular isn't loaded into memory yet. To deal with this, you must be loading your pages from a web server which supports URL rewrites. When the server receives a request for a URL that there isn't a physical page for, it rewrites the URL to load the base HTML page, where Angular can be loaded and take over.

When Angular receives a request for a route which has been rewritten in this manner, it must first determine what the intended route was. This is where the Base HTML Tag comes into play. Angular uses the Base reference to help it to determine which part of the URL is on the server, and which part is a client route. Essentially, where the # in the URL would be if Html5Mode was not enabled.

Unfortunately, Base is an HTML Tag that is used by the browser for more than just Angular. The browser also uses this tag to determine the correct location to load scripts and resources using relative paths from, regardless of the path in the location bar. In general, this isn't a problem if all of the scripts and resources are relative to the location of the Index.html file. When Base is omitted, the browser will load scripts from the apparent base path determined by the current URI. However, once you provide it, the browser will use whatever value you have supplied.

In general, unless you are hosting angular on a sub-page of your site and you want your users to expect something specific in the URL string, you should always control the base on your server, and use Base="/" on the client side.

Sign up to request clarification or add additional context in comments.

7 Comments

Just gotten around to reading it, I didn't downvote anything. Anyway, I've followed your logic, and applied base="/project/". So when inside the app, my routing is working fine as I have a template applied on /test which is loading the view fine. I came across the error you mentioned though where if I try to load project/test straight away without navigating to it from the homepage, then I get a 404 not found error. How do you normally overcome this issue?
@Claies the <base> tag also enables the browser to load the right resources regardless of the path that appears in the location bar. Otherwise, relative URIs resolve from the apparent base path of the current URI. No downvote from me but that's probably something you've missed in your explanation
I updated the question and added a link to that article that talks about how to set up URL rewrites on various servers.
@germainelol you wouldn't need the apache code if you are using node; that article is showing the technique for multiple different HTTP server types.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.