This is my angularjs routing
app.config(function($routeProvider, $locationProvider) {
$routeProvider.
when('/home', {
templateUrl: 'partials/home.html'
}).
otherwise({
redirectTo: '/'
});
if (window.history && window.history.pushState) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
}
});
This link works as expected
Home
However, when I type http://localhost:3000/home directly in the address bar, I get a blank page. Any idea why this is happening?
Typing http://localhost:3000/#/home redirects to http://localhost:3000/home and works as expected.
AngularJS in html5Mode uses html5 history routing to get rid of the # in the url. This works as long as you navigate in the webpage.
The browser requested your index.html once (which set up your app and especially ngRoute), and clicking Home etc. does not cause requests to the server. Instead, ngRoute looks up the route, manipulates the html5 history and shows you what you clicked.
However, you have to tell the browser that performs the localhost:3000/home request someone typed into the url bar that he in fact wants index.html (not home/index.html, which does not exist). This means you have to configure your server to support html5 history routing. The $location documentation has a long post about this.
Here's what you'd add if you use express:
// this must be the last middleware added to your express app
app.use(function(req, res) {
res.sendFile('index.html'); // specify the path to your index.html here
});
If you type /home directly to the address bar, you're asking the server for a document in the /home path, when you actually want the AngularJS application in a document in the root path to load the /home route. You need to configure your server to redirect any request other than the root path to the root path, and pass the specified path after a #, for example, redirect /home to #/home.
Angular uses ngRoutes to navigate without leaving the page. If your route contains the # sign followed by the route then you are still on the same page. Angular does this so that it can have persistent variables between views. If you redirect to /home instead of #/home you are loading a static path to the /home folder on your server and Angular will reload when the new page loads, all variables will be cleared.
Related
Before removing the hash sign, I had
mainApp.config(function ($locationProvider, $routeProvider) {
$routeProvider
.when('/page', {
controller: 'Page',
templateUrl: 'templates/page.html'
})
.when('/main', {
controller: 'Main',
templateUrl: 'templates/main.html'
})
.otherwise({ redirectTo: '/main'});
//$locationProvider.html5Mode(true);
});
and these worked fine
http://localhost:8080/index.html#/main
http://localhost:8080/index.html#/page
After removing the pound sign, I added to index.html
<base href="/">
<script src="/vendor/bootstrap-dist/js/bootstrap.min.js"></script>
<script src="/vendor/javascript/angular/angular.js"></script>
<script src="/vendor/javascript/angular/angular-route.js"></script>
<script src="/vendor/javascript/angular/ui-bootstrap-tpls-0.11.2.min.js"></script>
<script src="/javascript/index.js"></script>
<script src="/javascript/controllers/main.js"></script>
<script src="/javascript/controllers/page.js"></script>
and to index.js
$locationProvider.html5Mode(true);
now hitting http://localhost:8080 redirects to http://localhost:8080/main
but going to http://localhost:8080/main directly in the browser returns 404 and the other pages too
What should I do to fix the problem?
my backend is java
That's expected. Here's what happens when html5 is not turned on:
you enter the url http://localhost:8080/index.html#/main in the address bar
the browser makes a http request to localhost:8080/index.html and gets the html page as a response
the html page contains an angular application that is executed. The angular router parses the path after the hash (/main), and thus loads the associated view and controller
Now what happens when you enable html5 mode and load index.hml?
you enter the url http://localhost:8080/index.html in the address bar
the browser makes a http request to localhost:8080/index.html and gets the html page as a response
the html page contains an angular application that is executed. The angular router parses the path (/index.html), sees that it doesn't match any route, and thus changes the location in the address bar to the default: /main, and then loads the associated view and controller. Changing the location in the address bar doesn't make the browser do anything other than adding a new entry in its navigation history.
Now, what happens if you hit refresh, or directly enter http://localhost:8080/main in the address bar? Well in that case, you're saying the browser: "please load the page at the url http://localhost:8080/main. So that's what the browser does: it sends an HTTP request to http://localhost:8080/main. Since the server doesn't have anything at this address, it sends back a 404.
Now how to make it work? It's actually quite simple: you need to configure the server to send back the index.html page when it gets a request for the path /main (and for all the other paths of the angular application). That way, the browser will load the HTML page, the angular application it contains will be restarted, the angular router will parse the path (/main) from the URL, and it will thus load the view and the controller associated to that path.
So, I'm pretty new to AngularJS and I'm trying to use AngularJs ngRoute in my application.
It all works smoothly when I start at the application homepage:
http://localhost:8080/appName/
And when I click on links from this point it works smoothly.
However, when I type a URL that I know exists/works, it gives me a 404 error. If I go to that link by using the application instead of the url it loads fine, even though it has the same url.
Eg. http://localhost:8080/appName/search
will give a 404, even though that is the same url that is the default redirect.
Indeed, the only url that will load by typing in the location is the base URL I mentioned above.
My app.js looks like this:
app.config( ['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider){
$routeProvider
.when("/search", {
templateUrl: "search.html",
controller: "SearchController"
})
.when("/results", {
templateUrl: "results.html",
controller: "ResultsController"
})
.when("/browse", {
templateUrl: "browse.html",
controller: "BrowseController"
})
.otherwise({redirectTo:"/search"});
//This gets rid of the # on the urls to the templates
$locationProvider.html5Mode(true);
}]);
I am hosting this on a glassfish4 server.
Is there something obvious I am missing/misunderstanding about how ngRoute works? Is there some setting that I am missing?
All help appreciated...
EDIT 1: As #Matthew Green below says, I need to configure the webserver to return the index.html for all pages below
http://localhost:8080/appName
I know I am being completely dense here, but where abouts is this configured? I am hosting the code in a MAVEN Jersey-Quickstart-Webapp.
When you use ngRoute, you are using javascript to handle routing to create a SPA. That means you need to hit a real page that loads your routing for your application to know what page to route to.
For example, your http://localhost:8080/appName/ should be routing to your index.html which would contain the javascript for your routing. With that page loaded it knows how to handle the links you have in your application. However, if you were to go directly to http://localhost:8080/appName/pageName you also need that to load index.html, as it is the one that loads your routing. Once your routing is loaded it should direct you to the correct page in your application. Without redirecting in place, http://localhost:8080/appName/pageName is not a real page and therefore correctly returns a 404.
Knowing this, the thing you have to figure out is what kind of server setup you have to configure the appropriate redirects for everything under http://localhost:8080/appName/ to go to your index.html page.
Before removing the hash sign, I had
mainApp.config(function ($locationProvider, $routeProvider) {
$routeProvider
.when('/page', {
controller: 'Page',
templateUrl: 'templates/page.html'
})
.when('/main', {
controller: 'Main',
templateUrl: 'templates/main.html'
})
.otherwise({ redirectTo: '/main'});
//$locationProvider.html5Mode(true);
});
and these worked fine
http://localhost:8080/index.html#/main
http://localhost:8080/index.html#/page
After removing the pound sign, I added to index.html
<base href="/">
<script src="/vendor/bootstrap-dist/js/bootstrap.min.js"></script>
<script src="/vendor/javascript/angular/angular.js"></script>
<script src="/vendor/javascript/angular/angular-route.js"></script>
<script src="/vendor/javascript/angular/ui-bootstrap-tpls-0.11.2.min.js"></script>
<script src="/javascript/index.js"></script>
<script src="/javascript/controllers/main.js"></script>
<script src="/javascript/controllers/page.js"></script>
and to index.js
$locationProvider.html5Mode(true);
now hitting http://localhost:8080 redirects to http://localhost:8080/main
but going to http://localhost:8080/main directly in the browser returns 404 and the other pages too
What should I do to fix the problem?
my backend is java
That's expected. Here's what happens when html5 is not turned on:
you enter the url http://localhost:8080/index.html#/main in the address bar
the browser makes a http request to localhost:8080/index.html and gets the html page as a response
the html page contains an angular application that is executed. The angular router parses the path after the hash (/main), and thus loads the associated view and controller
Now what happens when you enable html5 mode and load index.hml?
you enter the url http://localhost:8080/index.html in the address bar
the browser makes a http request to localhost:8080/index.html and gets the html page as a response
the html page contains an angular application that is executed. The angular router parses the path (/index.html), sees that it doesn't match any route, and thus changes the location in the address bar to the default: /main, and then loads the associated view and controller. Changing the location in the address bar doesn't make the browser do anything other than adding a new entry in its navigation history.
Now, what happens if you hit refresh, or directly enter http://localhost:8080/main in the address bar? Well in that case, you're saying the browser: "please load the page at the url http://localhost:8080/main. So that's what the browser does: it sends an HTTP request to http://localhost:8080/main. Since the server doesn't have anything at this address, it sends back a 404.
Now how to make it work? It's actually quite simple: you need to configure the server to send back the index.html page when it gets a request for the path /main (and for all the other paths of the angular application). That way, the browser will load the HTML page, the angular application it contains will be restarted, the angular router will parse the path (/main) from the URL, and it will thus load the view and the controller associated to that path.
AngularJS - html5Mode - Cannot GET /login
So I have seen this post and my problem is very similar. I have used base tag to get my relative urls to work. And I have $locationProvider.html5Mode(true); in my application. Everything seems to work fine to keep /#/ urls out of the application, but when the user refreshes the browser it says page not found. The url it is going to is where my router should be pointing to:
$routeProvider
.when('/', {
templateUrl: 'views/coverPage.html',
controller: 'MainCtrl'
})
.when('/coverPage', {
templateUrl: 'views/coverPage.html',
controller: 'MainCtrl'
})
This is just an example of my router page. Again, this works when I link through a button, but when I load the url: http://www.someurl.com/somepath/coverPage it says page not found.
If it works fine, when navigating from a link but get a page not found when you refresh it appears to be a server side issue.
Be sure to acutally load the right angular app from the server at the specified url. You need a kind of wildcard url matching for the server side route. But without knowing more details of your application I can only guess.
I'm testing a website locally on my machine. It uses AngularJS for routing and page changes, and I'm attempting to test the routes using the Mongoose webserver (extremely light).
My code is as follows:
app.config(['$locationProvider', '$routeProvider', function ($locationProvider, $routeProvider) {
$locationProvider.html5Mode(true);
$routeProvider.when('/who', {templateUrl: '/js/partials/who', controller: 'whoPage'});
$routeProvider.when('/what', {templateUrl: 'partials/what'});
$routeProvider.when('/want', {templateUrl: 'partials/want'});
$routeProvider.otherwise({ redirectTo: '/' });
}]);
(I haven't set up controllers for some of the other pages yet. I've been testing the "who" page.)
I'm running the page from localhost:8080. In my application, when I click a link to change the location, nothing happens. The URL changes to "localhost:8080/who", but I get no messages from console, and I get no changes on my page. However, if I then refresh that URL, I get a 404 error.
I don't have any server-side routing set up. Is this a necessity for Angular apps? Is there something wrong with the code I've written, or should I try a different test webserver?
$locationProvider.html5Mode(true);
will make angular use "push state" from the HTML5 History API.
This means that you'll see the url change in the location bar, but that won't cause the browser to actually reload your page. When you reload the page, the browser will now fetch that url from the webserver, which doesn't have it.
A common trick is to use URL rewrites to map any url back to index.html. You should take care of not remapping the urls that point to static files such as your javascript and css resources. That's usually easy because it's a good practice to group all your css and js files in some directory instead of scattering them in the top level dir.
You can read about how to configure mongoose URL rewrites at https://www.cesanta.com/developer/binary#_url_rewrites