Angular2 Router not working correctly - node.js

I am trying to define a simple application with login functionality in Angular2 with Typescript. I have defined my Router but am getting an error when attempting to access the url in a browser. This is the error:
Cannot GET /login
And the url I am using:
http://localhost:3012/login
It seems as if router is not correctly routing the URL to correct component and I am not sure why. Here is my home.component.ts which instantiates the app and router:
import {Component} from 'angular2/core';
import {ROUTER_DIRECTIVES, RouteConfig} from 'angular2/router';
import {LoginComponent} from './login/login.component';
import {DashboardComponent} from './dashboard/dashboard.component';
#Component({
selector: 'home',
templateUrl: '<router-outlet></router-outlet>',
directives: [ROUTER_DIRECTIVES]
})
#RouteConfig([
{path: '/login', name: 'Login', component: LoginComponent, useAsDefault: true},
{path: '/dashboard', name: 'Dashboard', component: DashboardComponent},
{path: '/*other', name: 'Other', redirectTo: ['Login']}
])
export class HomeComponent {
}
Both the Login and Dashboard components are defined correctly and PHPStorm has not picked up any errors.
Does anyone have any idea as to why this may be happening?
Here is my server side code. server.ts (NodeJS entry point)
import express = require('express');
import path = require('path');
let port: number = process.env.PORT || 3012;
let app = express();
app.set('views', path.join('./src/Client/views'));
app.set('view engine', 'ejs');
app.engine('html', require('ejs').renderFile);
app.use("/node_modules", express.static(path.resolve(__dirname, '../../node_modules')));
app.use("/app", express.static(path.resolve(__dirname, '../Client/app')));
app.use("/*.html", function(req, res) {
res.render(req.params[0] + ".html");
});
app.get('/', function(req: express.Request, res: express.Response) {
res.render('index.html');
});
let server = app.listen(port, function() {
let host = server.address().address;
let port = server.address().port;
});
And my index.html file which includes all required Angular2 scripts and starts SystemJS
<html>
<head>
<title>Test</title>
<script src="node_modules/es6-shim/es6-shim.min.js"></script>
<script src="node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="node_modules/angular2/es6/dev/src/testing/shims_for_IE.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/rxjs/bundles/Rx.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<script src="node_modules/angular2/bundles/router.dev.js"></script>
<script src="node_modules/angular2/bundles/http.dev.js"></script>
<script>
System.config({
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
}
});
System.import('app/bootstrap')
.then(null, console.error.bind(console));
</script>
</head>
<body>
<home>Loading...</home>
</body>
</html>
And my file structure:
Thanks

I think this:
app.use("/*.html", function(req, res) {
res.render(req.params[0] + ".html");
});
should be
app.use("/*", function(req, res) {
res.render(req.params[0] + ".html");
});
because I am not sure why you would +.html again to a html request.
Does that solve the issue ?

I believe the router needs to have the base href set so it knows what you're routing relative to.
Angular 2 router no base href set

Related

Why is app.use() not serving up the 'public' directory when I save even though the path is appears to be correct?

I'm following a slightly outdated tutorial on node and express, and my code is identical to the tutorial, but app.use is not serving up the public directory as I wish. When I go to the root localhost:3000 I still see Weather like in the tags on line 19. When I delete it, I don't see anything, including the public directory's index.html file.
Here is my index.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge"> -->
<title>Document</title>
</head>
<body>
<h1>From a static file.</h1>
</body>
</html>
Here is my app.js script:
/* nodejs script that will create, configure, and start the server.
run script: node src/app.js
keep server running: nodemon src/app.js
*/
const path = require('path');
const express = require('express');
const app = express();
const publicDirectoryPath = path.join(__dirname, '../public'); // abs path to serve
// STACKOVERFLOW - WHY ISN'T THIS SERVING UP PUBLIC DIRECTORY?
app.use(express.static(publicDirectoryPath)); // serve 'public' directory
// create root route
app.get('/', (req, res) => {
res.send('<h1>Weather</h1>');
});
// create a help route
app.get('/help', (req, res) => {
res.send([
{name: 'Barack H. Obama'},
{name: 'George W. Bush'},
{name: 'William J. Clinton'}
]);
});
// create an about route
app.get('/about', (req, res) => {
res.send('<h1>About</h1>');
});
// create a weather route
app.get('/weather', (req, res) => {
res.send({
forecast: 'rain',
location: 'Los Angeles'
});
});
// port 3000 is common development port, starts server
app.listen(3000, () => {
console.log('Server is up on port 3000'); // never displays in browser
});
it should be public instead ..public like this
const publicDirectoryPath = path.join(__dirname, 'public')
As app.js and public share the same parent directory at the same level. So ..public will point out to dir public outside src which is not available.

Serve pre-made gzip files

I use compression-webpack-plugin to make gzip files durring my bundle process, so when bundling is done I have files like this in my dist folder.
bundle.eefaef91f71795847e74.js
bundle.eefaef91f71795847e74.js.gz
vendor.jduu4f4lj71759dj7e74.js
vendor.jduu4f4lj71759dj7e74.js.gz
stylesLocal.b7ac53d721aca93e4e65099cf74dc90f.css
stylesLocal.b7ac53d721aca93e4e65099cf74dc90f.css.gz
Inside server I use express-static-gzip to serve my gzip files. Why isn't this working. My page doesnt even wanna load? If I put Express.static instead of expressStaticGzip it works normally.
import Express from 'express'
import path from 'path'
import conf from './conf'
import appRenderer from './appRenderer'
import webpackUtils from './webpackUtils'
var expressStaticGzip = require('express-static-gzip')
const APP_PORT: number = conf.APP_PORT
const PORT: any = process.env.PORT || APP_PORT
const app: Express = new Express()
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')
app.use(expressStaticGzip(path.join(__dirname, '../', 'dist')))
/* check with the server before using the cached resource */
app.use((req: Object, res: Object, next: () => void): void => {
res.set('Cache-Control', 'no-cache')
return next()
})
/* Use server side rendering for first load */
app.use(appRenderer)
/* Use CommonChunks and long term caching */
app.use(webpackUtils)
// Routes
app.get('*', (req: Object, res: Object) => {
res.render('index', {app: req.body})
})
app.listen(PORT, () => {
console.log(`
Express server is up on port ${PORT}
Production environment
`)
})
And I refernce them in my index.ejs file.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>D</title>
<link rel='stylesheet' type='text/css' href="stylesLocal.b7ac53d721aca93e4e65099cf74dc90f.css">
</head>
<body>
<div id="app"><%- app %></div>
<script src="vendor.jduu4f4lj71759dj7e74.js"></script>
<script src="bundle.eefaef91f71795847e74.js"></script>
</body>
</html>
As explained in the readme of express-static-gzip, the syntax is slightly different from express.static.
Instead of
app.use(expressStaticGzip(path.join(__dirname, '../', 'dist')))
try
app.use('/', expressStaticGzip(path.join(__dirname, '../', 'dist')))

Express static css not served

I have been trying to figure this out for hours and my head is about to explode. I really hope it's not some stupid little detail I missed...
I have a server-side rendering react application set-up. Everything is going fine. The only problem I have is that I can't seem to get the css to load.
Here is my file tree (without node_modules): https://i.stack.imgur.com/xevUb.png'
I have the following code in my server.js file
app.use('static', express.static(__dirname + '/public'));
app.use('dist', express.static(__dirname + '/dist'));
app.get('*', (req, res) => {
match({
routes,
location: req.url
}, (error, redirectLocation, renderProps) => {
if (error) {
res.status(500).send(error.message)
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search)
} else if (renderProps) {
var html = renderToString( < RouterContext { ...renderProps
}
/>);
res.status(200).send(template({
body: html
}));
}
else {
res.status(400).send('Not found.')
}
});
});
And this is my template.js file :
export default ({ body }) => {
return `
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
<link rel="stylesheet" href="/static/css/style.css" />
</head>
<body>
<div id="root">${body}</div>
</body>
<script src="dist/client.js"></script>
</html>
`;
};
When I go on my local server. I get the html delivered and the bootstrap styles are applied to it. However, I get a 400 bad request error for the style.css and client.js linked in my template.js file.
I really hope someone can help me out on this one...
EDIT
Here is what I see on the developer console :
Your server.js file appears to be inside your dist folder, which means that __dirname would be ./dist instead of ./ like your code seems to be written. What you need to do is something like this:
const path = require('path')
const projectRoot = path.resolve(__dirname, '../')
app.use('static', express.static(projectRoot + '/public'))
app.use('dist', express.static(__dirname))

Angular 2 Router: Cannot match any routes

When trying to load localhost:3000/verifyemail in my browser, I receive the error:
Error: Cannot match any routes
I've read through the other SO questions on this, and have verified the following:
Angular2: 2.3.1 uses Path Location Strategy by default, and I haven't changed it. I prefer not to use Hash Location Strategy
I've configured my Nodejs server for HTML5 pushState (server.js is below)
// Parsers for POST data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// Point static path to dist
app.use(express.static(path.join(__dirname, 'dist')));
// Get API routes
const api = require('./src/server/routes/api.js');
// Set api routes
app.use('/api', api);
// Catch all other routes and return the index file
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
const port = process.env.PORT || '3000';
app.set('port', port);
const server = http.createServer(app);
server.listen(port, () => console.log(`API running on localhost:${port}`));
I have <base href="/"> at the top of my <head> in my index.html
I have default and catch-all routes set
const appRoutes: Routes = [
{ path: 'home',
outlet: 'full-page',
component: DefaultLandingPageComponent
},
{ path: 'verifyemail',
outlet: 'full-page',
component: EmailVerificationComponent
},
{ path: '',
redirectTo: '/home',
pathMatch: 'full'
},
{ path: '**',
outlet: 'full-page',
component: DefaultLandingPageComponent
}
];
I've imported the router module into my app.module.ts, and included a router outlet in my app.component.html file
//in app.module.ts:
#NgModule({
...
imports: [
...
RouterModule.forRoot(appRoutes)
]
...
});
//in app.component.html
import { RouterModule, Routes } from '#angular/router';
Thanks a lot to whoever can give me a hand with this!
Update 1
I've removed all names from routes and the router outlet, thanks to Günter Zöchbauer's observation in the comments below
Update 2
Everything works as expected on localhost:4200/verifyemail, which is run via ng serve.
Problem persists when using localhost:3000/verifyemail, which is run via node server.js
Each route needs a route that adds a component to an unnamed outlet.
Named outlets can only be used in addition to an unnamed outlet, not instead of.

Node/Express with Angular 2

I am trying to build the ToDo app with the MEAN stack and I can't get the Express server to connect to Angular 2. I believe it has something to do with where I have my index.html view relative to the Angular installation, but I can't figure it out.
The error I am getting is the HTML on index.html is rendering but not picking up the logic behind the selector so my assumption is my tags are wrong or something. I have tried every which way to adjust the tags, but I can't get it to work when running server.js. I know it is something silly but been working on this for a while.
Server.js
var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var index = require('./routes/index');
var todos = require('./routes/todos');
var app = express();
// View Engine
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.engine('html', require('ejs').renderFile);
app.use(express.static(path.join(__dirname,'client'))); //folder where angular will be
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use('/', index);
app.use('/api/v1/', todos);
app.listen(3000, function(){
console.log('Server started on port 3000...');
});
Index.html (in Views folder)
<!DOCTYPE html>
<html>
<head>
<title>Angular QuickStart</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="src/styles.css">
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="src/systemjs.config.js"></script>
<script>
System.import('src/main.js').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>Loading AppComponent FROM SERVER SIDE content here ...</my-app>
</body>
</html>
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppComponent } from './app.component';
#NgModule({
imports: [ BrowserModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
app.component.ts
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: `<h1>Hello {{name}}</h1>`,
})
export class AppComponent { name = 'Angular'; }
Below are the two errors I am getting in the console:
GET http://localhost:3000/src/app/app.module 404 (Not Found)
scheduleTask # zone.js:1960 ZoneDelegate.scheduleTask # zone.js:349
(404 Not Found) loading http:…pp.module" from
http://localhost:3000/src/main.js", originalErr:
ZoneAwareError}
Any help would be much appreciated, I can't get past this.
It is not liking something about the reference in this line and getting lost somewhere in zone.js, but I can't get it right. I am using the starter kit from angular.io and using their file layout.
System.import('src/main.js').catch(function(err){ console.error(err); });
I was able to fix by adding two more static routes to the express server so it looked in every folder.
app.use(express.static(path.join(__dirname, 'client'))); // folder where angular will be installed
app.use(express.static(path.join(__dirname, 'client', 'src')));
app.use(express.static(path.join(__dirname, 'client', 'src', 'app')));
This fixed the issue.
I have encountered the same problem with the new version of Quickstart. The fact that it has a different structure (src folder added) affects how express will behave. In my scenario I have NOT altered this portion.
System.import('src/main.js').catch(function(err){ console.error(err); });
Instead I left it as default (I believe angular handles where to look for it).
System.import('main.js').catch(function(err){ console.error(err); });
I have added one more static route. Make sure you have both, one of them will not suffice.
app.use(express.static(path.join(__dirname, 'client')));
app.use(express.static(path.join(__dirname, 'client/src')));
if you are following the TRAVERSY MEDIA: (original Source is EDUONIX)
https://www.youtube.com/watch?v=PFP0oXNNveg&t=2304s
after creating the 'client' folder. Skip the whole JSON Part.
Open Terminal
git clone https://www.github.com/angular/quickstart client
npm install
npm start (this will give you the complete start of the angular front-end)
ctrl + C (close the webserver)
npm run build
server.js
var express = require ('express');
var path = require ('path');
var bodyParser = require ('body-parser');
var index = require ('./routes/index');
var todos = require ('./routes/todos');
var app = express();
//View Engine
app.use(express.static( path.join(__dirname, 'client') ) );
app.use(express.static( path.join(__dirname, 'client/src')));
app.use(express.static( path.join(__dirname, 'client/bower_components')));
app.set('views', path.join(__dirname, 'client/src') );
app.set('view engine', 'ejs');
app.engine ('html', require('ejs').renderFile );
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false} ));
app.use('/', index);
app.use('/api/v1', todos);
app.listen(3000, function() {
console.log ('server started on port 3000');
/routes/index.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('index.html');
});
module.exports = router;
Last but not the least:
make sure this route would execute:
http://localhost:3000/api/v1/todos
yes? (you did it)

Resources