Note: I tried all questions & answer related this topic. Like This and I tried related questions and try to solve it but not success.
I am building angularJS web-app. It's purely based on AngularJS/HTML5 and NodeJS/ExpressJS and Database side use mongo DB then this problem occurs.
I want To '#'
remove in url and I refresh page then display my current page .But right now display "Not Found 404".I use like this $locationProvider.html5Mode(true);
and <base href="/" />
but I am not success.
I know remove # in URL solution is
$locationProvider.html5Mode(true);
and<base href="/" />
But i use NodeJS/ExpressJS then I can't use.
My Url
http://localhost:3000/Tutorial/Routing/StateProvider/index.html#/Setting/StudenList
I want to URL
http://localhost:3000/Tutorial/Routing/StateProvider/index.html/Setting/StudenList
Notes:
Without this Solution $locationProvider.html5Mode(true);
and
<base href="/" />
But i use NodeJS/ExpressJS Then I want to remove # and refreshing page issue solve
Code
Folder Structure directive
.my code very long then i mange snippet (inside html & js ). Not run snippet because i insert all my code just for understand what is mistake my code.
sample2(refreshissue) [Project Name]
-- Public
-- Tutorial
--Directive
-index.html
--Routing
--StateProvider
-Account.html
-index.html
-Setting.html
-StudentListing.html
-studentDetails.html
-StateProviderController.js
--Validation
-index.html
-index.html
-- StateProviderController.js
---------------------------------------------------------------------------------
var myapp= angular.module('myapp2',["ui.router"]);
myapp.config(function($stateProvider,$urlRouterProvider,$locationProvider,$urlMatcherFactoryProvider){
$urlMatcherFactoryProvider.strictMode(false);
$stateProvider
.state('TutorialHome', {
url:'/index',
templateUrl:'/index.html'
})
.state('Profile',{
url:'/Profile',
templateUrl:'Profile.html'
})
.state('Account',{
url:'/Account',
templateUrl:'Account.html'
})
.state('Setting',{
url:'/Setting',
templateUrl:'Setting.html'
})
.state('Setting.StudenListing', {
url:'/StudenList',
views: {
'StudenListing': {
templateUrl: 'StudenListing.html',
controller:'StudentListingData'
}
}
})
.state('Setting.StudenListing.StudentList',{
url:'/StudenList/:StudentID',
/* templateUrl: 'StudentDetails.html',
controller:'StudentDetails'*/
views:{
'StudentDetails': {
templateUrl: 'StudentDetails.html',
controller:'StudentDetails'
}
}
})
;
// $urlRouterProvider.otherwise('/index');
//$locationProvider.html5Mode(true);
});
myapp.controller('StateProviderCtrl',function($scope){
$scope.message ="Welcome To State Provider Page";
$scope.Home = function()
{
window.open('/',"_self");
}
});
myapp.controller('StudentListingData',function($scope,$http){
console.log('test');
$http.get('/StudenRecordData').success(function(response){
// console.log(response);
$scope.StudentRecorddata =response;
})
});
myapp.controller('StudentDetails',function($scope,$http,$stateParams){
$scope.StudentID = $stateParams.StudentID;
//console.log( $scope.StudentID);
$http.get('/StuentRecordSearch/'+ $stateParams.StudentID).success(function(response){
//console.log(response);
$scope.StuentDetails =response[0];
})
});
==================================================================================================================================================================
---- app.js
---------------------------------------------------------------------------------
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var url =require('url');
var index = require('./routes/index');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
/*var basepathArray = ['/Tutorial/Routing/StateProvider/','/Tutorial/Validation/','/Tutorial/Directive/'];
app.get('/!*',function(req,res){
var basePath ="";
for(var i=0;i<=basepathArray.length-1;i++)
{
if(req.originalUrl.search(basepathArray[i]) != -1){
basePath =basepathArray[i];
break;
}
}
if(basePath!="")
{
res.sendFile(path.resolve('public'+basePath+'index.html'));
}
else {
res.sendFile(path.resolve('public/index.html'));
}
});*/
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
=================================================================================
-- Account.html
---------------------------------------------------------------------------------
<h1>Account page</h1>
=================================================================================
-- index.html
---------------------------------------------------------------------------------
<!DOCTYPE html>
<html ng-app="myapp2">
<title>Index | Angular Js</title>
<base href="/Tutorial/Routing/StateProvider/" />
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<!--<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-route.js"></script>-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.2/angular-ui-router.js"></script>
<script src="StateProviderController.js"></script>
<body ng-controller="StateProviderCtrl">
<nav class="navbar navbar-default row">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" ui-sref="TutorialHome"> State Routing</a>
</div>
<ul class="nav navbar-nav">
<li><a ui-sref="Profile">Profile</a></li><!--State Transition on click-->
<li><a ui-sref="Account">Account</a></li><!--State Transition on click-->
<li><a ui-sref="Setting">Setting</a></li><!--State Transition on click-->
<li style="float: right;" ><a ng-click="Home()"> Home</a></li><!--State Transition on click-->
</ul>
</div>
</nav>
<div class="container" ng-controller="StateProviderCtrl">
<!-- we use ui-view instead of ng-view -->
<!--{{message}}<br>-->
<ui-view></ui-view>
</div>
</body>
</html>
=================================================================================
-- Profile.html
--------------------------------------------------------------------------------
<h1>Profile page</h1>
=================================================================================
-- Setting.html
---------------------------------------------------------------------------------
<div>
<h1>Setting page</h1>
<strong>This page shows Nested states & views. Click on below links to see Nested states in action.</strong><br>
<ul>
<li><a ui-sref="Setting.StudenListing">Show Listing</a></li>
</ul>
<div class="container">
<div class="row">
<div class="col-sm-12" style="background-color:beige;display: inline-block">
<div ui-view="StudenListing"></div>
</div>
</div>
</div>
</div>
<!-- <div ui-view="Descriptions"></div><br>
<div ui-view="Price"></div>-->
=================================================================================
-- StudentListing.html
---------------------------------------------------------------------------------
<!--<ui-view></ui-view>-->
<div class="row">
<div class="col-sm-6" style="background-color:beige;">
<h2>Student Listing</h2>
<p>All Talented Student List</p>
<table class="table" >
<thead>
<tr>
<th>Name</th>
<th>Eduction</th>
<th>Email ID</th>
<th>Details <!--<div ui-view="StudentDetails"></div>--></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="data in StudentRecorddata">
<td>{{data.Name}}</td>
<td>{{data.Eduction}}</td>
<td>{{data.Email}} </td>
<td><button type="button" class="btn btn-info" ui-sref="Setting.StudenListing.StudentList({StudentID:$index})">View Details</button> </td>
</tr>
</tbody>
</table>
</div>
<div class="col-sm-6" style="background-color:beige;">
<!-- <div ui-view="StudenListing"></div>-->
<div ui-view="StudentDetails"></div>
</div>
</div>
=================================================================================
-- studentDetails.html
------------------------------------------------------------------------------<div>
<h2>Student Details </h2>
<br>
<form class="form-horizontal">
<div class="form-group">
<label class="control-label col-sm-2" for="email">Stuent Id:</label>
<div class="col-sm-10">
<p class="form-control-static">{{StudentID}}</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="email">Name:</label>
<div class="col-sm-10">
<p class="form-control-static">{{StuentDetails.Name}}</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="pwd">Age:</label>
<div class="col-sm-10">
<p class="form-control-static">{{StuentDetails.Age}}</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="email">Eduction:</label>
<div class="col-sm-10">
<p class="form-control-static">{{StuentDetails.Eduction}}</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="pwd">Email:</label>
<div class="col-sm-10">
<p class="form-control-static">{{StuentDetails.Email}}</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="email">MobileNumber:</label>
<div class="col-sm-10">
<p class="form-control-static">{{StuentDetails.MobileNumber}}</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="pwd">Gender:</label>
<div class="col-sm-10">
<p class="form-control-static">{{StuentDetails.Gender}}</p>
</div>
</div>
</form>
</div>
In Express if we want to redirect the user to the 404 error page if a particular route does not exist then we can use the app. all() method as the last route handler method and * (asterisk) as the route name.
All you need to do is add a middleware function at the very bottom of the stack (below all other functions) to handle a 404 response: app. use((req, res, next) => { res. status(404).
This is because the web server receiving the request looks for a resource matching the full url on the server, which doesn't exist because the angular portion of the url refers to a route in your angular application and needs to be handled in the client browser
AngularJS + NodeJS/ExpressJS - Routes to prevent 404 error after page refresh in html5mode
var express = require('express');
var path = require('path');
var router = express.Router();
// serve angular front end files from root path
router.use('/', express.static('app', { redirect: false }));
// rewrite virtual urls to angular app to enable refreshing of internal pages
router.get('*', function (req, res, next) {
res.sendFile(path.resolve('app/index.html'));
});
module.exports = router;
AngularJS + IIS - URL Rewrite Rule to prevent 404 error after page refresh in html5mode (for apache click here)
<rewrite>
<rules>
<rule name="AngularJS" 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>
Referred from
additional way to fix this
https://stackoverflow.com/a/34817349/2218635
This is what I have for my app.
From the API docs for HTML5 mode
if (HTML5 mode is) enabled and requireBase are true, and a base tag is not present, an error will be thrown when $location is injected.
So, you need the base
tag. I've tried without the base tag and requireBase
to be false but it still seems to throw an error for me.
index.html
<head>
<base href="/">
</head>
app.route.js[Angular.js]
app.config(function($stateProvider, $urlRouterProvider, $locationProvider) {
// This removes '#' and makes URL pretty
$locationProvider.html5Mode({
enabled: true,
requireBase: true
});
// Default path if nothing is matched. State would become 'landing'
$urlRouterProvider.otherwise('/');
$stateProvider
.state('landing', {
url: '/',
templateUrl: "/dashboard/landing/templates/index.html",
controller: 'LandingController'
}).state('about', {
url: '/about',
templateUrl: "/dashboard/about/templates/index.html",
controller: 'AboutController'
});
});
Once you redirect yourself from 'landing'
to 'about'
state and the route changes to /about
, the URL is only changed on the browser and the server does not know of this. So, when you refresh, the server does not know what /about
path means. Thus, you need to redirect /about
path (or any path that belongs to angular's routes) to index.html
and then angular redirects you back to /about
automagically.
app.js[Express.js]
// dashboard route should deliver templates instead of loading angular JS app so this should come before the next one
app.use('/dashboard', express.static(__dirname + '/public/dashboard'));
// put all the API methods here and separate from the redirection to `index.html`
app.use('/api', routes.apiRoutes);
// all the paths that do not start with `/dashboard` or `/api` is/should be angular route and thus, redirect back to `index.html`
app.get('*', function (req, res) {
res.sendFile(__dirname + '/public/index.html');
});
Side note
On another app, I've seen an issue where refreshing the browser appends a trailing slash at the end of the path (/
) and after the redirection, Angular app could not recognize the path from the url /about
vs /about/
so it redirected me back to the landing page.
I resolved this by adding this in app.route.js
$urlMatcherFactoryProvider.strictMode(false);
I hope this helps
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With