I can't figure this out for the life of me. I'm using Node, Express, Angular and ui.route. What I'm trying to accomplish is the following,
have index.html as a master
have some.html as partials
I setup the application to use ejs instead of jade (don't know if that matters at all)?
The error I'm getting is that it can't find localhost:3000/views/partial-home.html 404, I tried all types of different paths in my routing,
(function(){
var app = angular.module('routerApp', ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/about');
$stateProvider
.state('home-about', {
url: '/home-about',
templateUrl: '/views/partial-home.html'
})
.state('about', {
});
});
}());
I do not have anything particular in my app.js file to handle html or in my route/index.js, currently I think it's using the index.ejs as well. What steps am I missing in using html and why could the error be with it not finding the partial-home.html
//routes/index.js
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
There are posts about this topic but none kinda sums up my two issues with using html files and why the 404. Appreciate all help I can get. Thanks!
You still need to 'mount' this router to the app.
app.use('/', router);
The router will be relative to the path that you mount it to, in this case the root /. You can mount it to any path and the router will be relative to that path. e.g.
app.use('/bar', router);
And your router 'mini-app' will be invoked when the application gets (or any other HTTP method) /bar/ path.
Hey you can set your app view engine as html such that it can render html file.
var ejs=require("ejs");
app.set('views',//folder path of views);
app.engine('html', ejs.renderFile);
app.set('view engine', 'html');
I got the solution. It's just one of those gotchas. I was looking into my app.js, I had all the routing correct as Arbel was helping me with.
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
So I was looking though the file and it hit me when I seen this line, right that this is a static resource.
app.use(express.static(path.join(__dirname, 'public')));
So I put my html files into public/partials and that was it.
Now my route look like this
$stateProvider
.state('home-about', {
url: '/home-about',
templateUrl: '/partials/partial-home.html'
});
Related
I am trying to get an input from my main site. After the input is submitted the page should redirect to /view. It seems like it successfully redirects to /view (because console.log() is getting triggered, but res.render is not working. If i manually go to /view it is rendering the page.
Here is the code of my app.js file:
// load the things we need
var express = require('express');
var app = express();
let bodyParser = require("body-parser");
let article = '';
//Set the view engine to ejs
app.set('view engine', 'ejs');
app.use('/static', express.static('static'))
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json())
//Index page
app.get('/', function (req, res) {
res.render('index')
});
//Get the input from the form
app.post('/searcharticle', function (req, res) {
article = req.body.article;
res.redirect('/view')
return article;
});
//Page to output the input
app.get('/view', function (req, res) {
console.log(article)
res.render('view', {
article: article
})
})
app.listen(8080);
console.log('Server on 8080');
And here is my
folder structure
Thank you for your help!
use view engine first then set the directory where to use it.
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
and for static files use
app.use('/static',express.static(PATH.join(__dirname+'/static'));
You have to mention the layout
app.get('/', function (req, res) {
res.render('index',{layout:false})
});
supposed you have al your .ejs files in views folder try adding this line in your code:
const path = require('path'); //npm install -S path in your console to install path.
//Set the view engine to ejs
app.set('views', path.join(__dirname, 'views')); // add this one, change 'views' for your folder name if needed.
app.set('view engine', 'ejs');
app.use('/static', express.static('static'))
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json())
If you are running your server from a diff directory than static you need to add a relative path
app.use('/static', express.static(__dirname+'/static'))
I was just given the solution to a very similar problem by my wonderful tutor. The login form 'submit' was passed to jQuery on('click') and after authetication called a Res.Render of the results of an API call. The API call result set was log-abled, but the page never rendered, and there was no error.
He told me that jQuery acts as a 'shadow' DOM, and that the Res.Render was likewise taking place in that shadow DOM. I changed the login form to a form Post instead of the jQuery on Click.
That WORKED!
I worked on this for several days without ever thinking jQuery could cause that obstacle.
My way is to go back the version of ejs to 2.5.2, and that works. However, I don't know the reason why it cannot support the version 3..
I'm using back4app BaaS service that uses Parse-Server. For the ClientSide I'm running AngularJS with html5Mode(true);
My problem is that this is NOT working: http://app.rizop.tv/dashboard
While this is working right: http://app.rizop.tv
Any idea how to fix expressJS to handle my routes in the right way?
I have this config:
cloud\app.js
// Helper modules that will be used
var path = require('path');
var bodyParser = require('body-parser')
// This imports the Router that uses the template engine
var index = require('./routers/index');
// Sets the template engine as EJS
app.set('view engine', 'ejs');
// This defines that the 'views' folder contains the templates
app.set('views', path.join(__dirname, '/views'));
// These options are necessary to
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
// This bind the Router to the / route
app.use('/', index)
// Starts listening in the routes
app.listen();
cloud\routers\index.js
// Importing express
var express = require('express');
// Creating a Router
var route = express.Router();
// Defining a route that binds the GET method
route.get('/', function(req, res) {
// This is the code that renders the template
res.render('index', {testParam: 'Back4Apper'});
});
module.exports = route;
cloud\views\index.ejs
<!doctype html>
<html>
<head>
<meta charset="utf-8">
...
</body>
...
</body>
</html>
Here is my app structure:
You can make it work by making little changes in app.js and root html file
I assume you already defined $locationProvider.html5Mode(true); where you defined your routes. Then define base href in your index html
<head>
<base href="/">
...
</head>
This answer might be helpful to configure your server
The file at cloud/app.js should not have app.listen() on its final line, due to the fact that you are using Cloud Code. Can you please try that?
I have ran into the same problem and did the following
I've put this route as the last option, so when the express router ran out of options it will render the index file where is the angular app. Angular internal router will resolve that route and draw the view.
router.get('*', function (req, res) {
res.render('index', {testParam: 'Back4Apper'});
});
Obviously you can write a smarter regex instead of * according to your needs but you get the idea.
(Update: I solved the problem. Just look at the end of the question)
I am running with this problem that seems trivial to me, but I am very frustrated because I am not able to figure it out:
I scaffolded an Angular application using yeoman generator-angular. I need to use the html5mode of Angular to get rid of the hashtag (please, see app.js below). I am using a node express server (see server.js) to run the app built with grunt build.
As required, I added the option in the server to redirect to index.html when accessing the app from any specific route. It works with one level of "routing", i.e., localhost:8080/research, but it does not work for two "levels" or more, i.e., localhost:8080/research/human. In this case, when refreshing the browser, I get this error:
The stylesheet http://localhost:8080/research/styles/vendor.8089f103.css was not loaded because its MIME type, "text/html", is not "text/css". human
The stylesheet http://localhost:8080/research/styles/main.e7eff4cf.css was not loaded because its MIME type, "text/html", is not "text/css". human
SyntaxError: expected expression, got '<' vendor.01f538ae.js:1:0
SyntaxError: expected expression, got '<'
I have searched everywhere, I have tried all sort of options, but I am not able to fix it. I would really appreciate some help, please!
app.js
angular
.module('testAngularApp', [
'ngRoute',
'ngTouch',
'ngAnimate',
'ngSanitize',
'angulartics'
])
.config(function ($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider
.when('/', {
templateUrl: 'views/mainFrontpage.html',
controller: 'MainFrontpageController'
})
.when('/research', {
templateUrl: 'views/research.html',
controller: 'ResearchController'
})
.when('/research/human', {
templateUrl: 'views/research-human.html',
controller: 'ResearchController'
})
.when('/research/fly', {
templateUrl: 'views/research-fly.html',
controller: 'ResearchController'
})
.otherwise ({
templateUrl: 'views/notyetready.html',
});
});
server.js
'use strict';
var express = require('express');
var path = require('path');
var morgan = require('morgan');
var fs = require('fs');
var currentDir = process.cwd();
var app = express();
var staticStats = fs.statSync( currentDir + '/dist');
if (staticStats.isDirectory()) {
app.use('/', express.static(currentDir + '/dist'));
// Here I have tried many different combinations
app.use("/styles", express.static(__dirname + "dist/styles"));
app.use("/scripts", express.static(__dirname + "dist/scripts"));
app.use("/views", express.static(__dirname + "dist/views"));
app.use("/fonts", express.static(__dirname + "dist/fonts"));
app.use("/templates", express.static(__dirname + "dist/templates"));
app.use("/images", express.static(__dirname + "dist/images"));
app.all('/*', function(req, res, next) {
// Just send the index.html for other files to support HTML5Mode
res.sendFile('dist/index.html', { root: __dirname });
});
var server = app.listen(8080);
console.log('Node Express server listening on http://%s:%d', server.address().address,8080);
}
else {
console.log('No /dist folder, did not start the server');
}
Update: Solution
Thanks to the comments of the users, I asked the question in a different way and found the solution that make it works here. That is, the <base href="/"> tag must be located before the <link rel="stylsheet"..> tags (what a hard time I got for such a stupid thing!)
Why not use nested routing in angular routing like this ?
https://github.com/angular-ui/ui-router
I wanted this to be just a comment but I can't yet, Have you tried placing the html5 mode below your routes ?
Can remove the if statement if you do not need it.
.when('/research/fly', {
templateUrl: 'views/research-fly.html',
controller: 'ResearchController'
})
.otherwise ({
templateUrl: 'views/notyetready.html',
});
if(window.history && window.history.pushState){
$locationProvider.html5Mode(true);
}
});
Maybe try using a different pattern to match against that sounds like the cause of the problem
app.all('/**/*', function(req, res, next)
However I would ask why are you serving the static files with node + express? If all you want is a static file server for local development why not try grunt-serve
Then if you want to serve the static files on a server you can use nginx which works really well with angular in html5 mode
I have a working Node.js site, using Express.js, Handlebars.js and Consolidate.js. I want to use partials for common parts of my templates, but can't work out how to make them work for pages at different URLs.
My /views/ directory contains this:
_footer.html
_header.html
article.html
index.html
The relevant parts of my Node app looks something like:
var express = require('express'),
consolidate = require('consolidate'),
handlebars = require('handlebars'),
path = require('path');
var app = express();
app.engine('html', consolidate.handlebars);
app.set('view engine', 'html');
app.set('views', path.join(__dirname, '/views'));
var partials = {header: '_header', footer: '_footer'};
app.get('/', function(req, res) {
res.render('index', {partials: partials});
};
app.get(/^\/([\w-]+)\/$/, function(req, res) {
res.render('article', {partials: partials});
};
And in my index.html and article.html Handlebars templates I have something like:
{{> header}}
<!-- page content here -->
{{> footer }}
I should be able to access both / (when index.html is rendered) and /foo/ (when article.html is rendered). But it only works for whichever I try to access first after starting the Node server. When I then navigate to the other path, I get errors like:
Error: ENOENT, no such file or directory '/Users/phil/Projects/projectname/views/<!DOCTYPE html>...
with the rest of the _header.html partial following.
I assume I need to somehow set the path to my partials to be absolute somehow, but I can't see how to do that.
For consolidate check that : https://github.com/tj/consolidate.js/issues/18
I would recommend to switch to something a bit more specific like that https://github.com/donpark/hbs it will be simpler.
I had the same exact issue. It seems that consolidate is reusing the "partials" object that you pass, replacing the values with the file content (yuck!).
A workaround is to create a new "partials" object every time. If you don't want to rewrite the whole object every time, you can use a function returning the object literal.
In your case something like the following should work:
var express = require('express'),
consolidate = require('consolidate'),
handlebars = require('handlebars'),
path = require('path');
var app = express();
app.engine('html', consolidate.handlebars);
app.set('view engine', 'html');
app.set('views', path.join(__dirname, '/views'));
var partials = function() {
return {header: '_header', footer: '_footer'};
}
app.get('/', function(req, res) {
res.render('index', {partials: partials()});
};
app.get(/^\/([\w-]+)\/$/, function(req, res) {
res.render('article', {partials: partials()});
};
Not really elegant, but I don't think there is really a way to keep it simpler.
I bought the latest nodejs peepcode tutorial and followed it, however I can't get past the initial step.
I'm getting frustrated after spending several hours to find out where I got an error since debugging nodejs is a riddle for me.
app structure looks like this:
example
|__public
|__views
|__assets
|__apps <- instead of routes
server.js
package.json
Here is my simple code:
server.js
/**
* Module dependencies.
*/
require('coffee-script');
var express = require('express');
var app = module.exports = express.createServer();
// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(express.errorHandler());
});
// routes
require('./apps/authentication/routes')(app);
app.listen(3000);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
/apps/authentication/routes.coffee:
routes = (app) ->
app.get '/login', (req, res) ->
res.render "views/login",
title: 'Login'
stylesheet: 'login'
module.exports = routes
apps/authentication/views/login.jade template:
form(action='/sessions', method='post')
label
| Username
input(type='text', name='user')
label
| Password
input(type='password', name='password')
input(type='submit', name='Submit')
nothing fancy, i got a stylesheet file and login.css in public/stylesheet/login.css
instead of a login template from authentication/routes.coffe when browsing http://localhost:3000/
Cannot GET /
no any other error message from node either:
Express server listening on port 3000 in development mode
I can't figure out where the problem is and this is really frustrating.
Probably some dumb typo somewhere but I can't figure this out :(
You do not have a route configured for the root '/'. Navigating to http://localhost:3000/login should return your login view as specified by the route to the resource '/login'. You need to add something along the lines of:
app.get '/', (req, res) ->
#if not logged-in then send to /login else
res.render('/views/authenticated', 'Home', 'index')
For more details on routing see http://expressjs.com/guide.html#routing.
It looks like everything is working as intended. The problem is that you haven't defined a route that matches the request GET /. You've only defined a route matching GET /login in your routes.coffee; also, GET /anythinginyourpublicdir will work thanks to the express.static middleware.