Reputation: 113
My app is "working" fine, but, when I press F5 in browser my problem appears.
My app is organized this way:
nodeJs + express, in Express :
app.use(express.static('public'));
app.use( app.router );
app.use(function(req, res) {
res.sendfile(__dirname + '/public/index.html');
});
my angular routes:
app.config(function($locationProvider, $routeProvider) {
$locationProvider
.html5Mode(true)
.hashPrefix('!');
$routeProvider
.when('/', { templateUrl: '/page/home.html'})
.when('/activate/:token', { templateUrl: '/page/activate.html'})
.otherwise({ redirectTo: '/' });
});
and everything is working fine until i refresh the page, if i'm on localhost:1234/activate/999 it appear refreshing good the page, but it stamp in console this error
Error: Template must have exactly one root element. was:<!DOCTYPE html>
<html ng-app=app xmlns="http://www.w3.org/1999/html">
<head>
<title>title</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
bla
bla
bla
all my index.html!
what can be the problems?
any solutions?
edit:
my home:
<div>
<section id="feature_slider" class="">
//...
</section>
<div id="showcase">
//...
</div>
<script type="text/javascript" src="/js/index-slider.js"></script>
</div>
mi activate:
<div>
test
</div>
my index.html
<!DOCTYPE html>
<html ng-app=app xmlns="http://www.w3.org/1999/html">
<head>
<title>tite</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Styles -->
<link href="/css/bootstrap.min.css" rel="stylesheet">
<link href="/css/bootstrap-responsive.min.css" rel="stylesheet">
<link href="/css/bootstrap-overrides.css" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="/css/theme.css">
<link rel="stylesheet" href="/css/index.css" type="text/css" media="screen" />
<link rel="stylesheet" type="text/css" href="/css/lib/animate.css" media="screen, projection">
<link rel="stylesheet" href="/css/sign-in.css" type="text/css" media="screen" />
<link rel="stylesheet" href="/css/myCss.css" type="text/css"/>
</head>
<body class="pull_top">
<navbar>
//...
</navbar>
<ng-view> Loading...
</ng-view>
<!-- starts footer -->
<footer id="footer">
//...
</footer>
<!--Preload-->
<script src="/js/jquery-1.10.1.min.js"></script>
<!-- Scripts -->
<script src="/js/bootstrap.min.js"></script>
<script src="/js/theme.js"></script>
<!--Angular-->
<script type="text/javascript" src="/js/angular.min.js"></script>
<!--<script type="text/javascript" src="/js/angular-ui.min.js"></script>-->
<script type="text/javascript" src="/js/ui-bootstrap-0.5.0.min.js"></script>
<script type="text/javascript" src="/angular/app.js"></script>
<!--Angular Controller-->
<script type="text/javascript" src="/angular/login/loginController.js"></script>
<script type="text/javascript" src="/angular/menuNavBar/menuController.js"></script>
<script type="text/javascript" src="/angular/login/logOutController.js"></script>
<script type="text/javascript" src="/angular/login/registerController.js"></script>
<!--Angular Services-->
<script type="text/javascript" src="/angular/alertBox/messageBoxController.js"></script>
<!--Router-->
<script type="text/javascript" src="/angular/router/router.js"></script>
</body>
Upvotes: 2
Views: 3802
Reputation: 1041
This is a problem commonly encountered when using a "catch-all" route that returns index.html (which you have to do when using Angular's html5 mode).
I don't know what your public folder structure looks like, but your Angular is making a request for activate.html that doesn't match its actual location (as served by Express). It may be because you have a leading slash in your templateUrl:
{ templateUrl: '/page/activate.html'})
but that depends on what your public folder looks like. "/page/activate.html" assumes that the "page" folder is at the root of your public folder. If it isn't, then that's your problem. You should have:
{ templateUrl: 'path/relative/to/public/folder/page/activate.html'})
which I'm guessing in your case would be something like:
{ templateUrl: 'views/page/activate.html'})
(It doesn't seem likely there would be a folder called "page" at the root of public/.)
Your express middleware attempts to handle the request for
http://localhost:1234/page/activate.html
but nothing successfully handles it, so your catch-all route just returns index.html, which has multiple root elements, causing Angular to throw a fit. Angular expected activate.html but it got index.html instead.
This will happen whenever the client makes a request that Express can't handle, because the catch-all router will return index.html. You can get your browser in an infinite loop as it continuously loads index.html, which loads Angular, which (erroneously) loads index.html, which loads Angular, etc.
Look at the request your browser is making for activate.html and make it match the actual location (as served by Express) of activate.html.
Upvotes: 3
Reputation: 54514
Try use the specify the templateUrl with the absolute path from the root
of the views.
For example, suppose you have configured and views
is in the public
folder
app.set('views', __dirname + '/public');
then change the path to the template to
/public/page/home.html
Upvotes: 0