Serve Different Angular Apps on Different Express Routes - javascript

I want to serve two defferent angular apps on two different routes: domain.com/admin for admin app and domain.com/customer for customer app.
app.use("/admin", express.static(path.join(process.cwd(), "web/dist/admin")));
app.use("/customer", express.static(path.join(process.cwd(), "web/dist/customer")));
app.get("/admin/**", (req, res) => {
res.sendFile(path.join(process.cwd(), "web/dist/admin/index.html"));
});
app.get("/customer/**", (req, res) => {
res.sendFile(path.join(process.cwd(), "web/dist/customer/index.html"));
});
This works, apps are on the routes where they have to be. But I'm getting these error from angular:
Seems like angular can't get files from the server. Is there something like baseUrl, a path for angular to get the files from?

Related

How to render multiple static files in express?

I am trying to use express to render a few different html files from my public folder. These are all static files. I also want to render a 404 page if a route is an invalid route is called. Here is my code.
const express = require("express")
const app = express()
app.use(express.static("public"))
app.get("/", (req, res) => {
res.render("index")
})
app.get("/about", (req, res) => {
res.render("about")
})
app.get("/contact-me", (req, res) => {
res.render("contact-me")
})
app.get("*", (req, res) => {
res.status(404).send("404 for all pages not defined in routes")
})
app.listen(8080)
The first route to render index.html works and the 404 status works, but all the other routes give me an error of "No default engine was specified and no extension provided." I tried added an ejs view engine, but the code still doesn't work. All html files are named properly and live in the "public" folder. Any help on this would be amazing! Thanks much!
You need to use handlebars for handling it. To see an example check this repo

Multiple React apps on express

I have a server on express.js and there is a static folder in its root directory, it contains several react apps, something like this:
app:
static:
react1
react2
I am trying to make sure that when accessing the /react1 and /react2 addresses, the express will display the required application.
app.js:
app.use (express.static(path.join(__ dirname, "static")));
app.use ("/", indexRouter);
index.router:
router.get('/react1', (req, res) => {
res.sendFile(path.join (__dirname, '..', 'static', 'react1', 'index.html'))
});
router.get('/react2', (req, res) => {
res.sendFile(path.join (__dirname, '..', 'static', 'react2', 'index.html'))
});
When I try to navigate through these handles, I get a blank page. What am I doing wrong?
Your app.js & index.router looks fine.
You might wanna add * to the router.
For instance
router.get('/react1/*', (req, res) => {
I think the issue is in how the static content is built.
Make sure to add PUBLIC_URL to build script in package.json.
For instance: "build": "PUBLIC_URL=/admin react-scripts build",
You can refer this youtube video for a detailed explanation.

How to let backend file (app.js) process any url comes from the frontend

I have an Express app contains two files on the root
(index.js + index.html)
and a folder named: server, contains a file [app.js] that listening to port 3000
I run index.html through Live Server on port: 5500
In [index.html + index.js] I fetch data through buttons from port 3000 where app.js is listening on, and it working good.
But my problem is when the user type a link in the frontend (localhost:5500/NotFound), in this case the browser won’t find the link and will get an error: Cannot Get…
What I want is to show a message “Not Found” for any invalid URL comes from the frontend
my question isn’t about 404 error itself but how to let the frontend handles the navigation in the backend.
my app structure is like this:
//app.js on port:3000/backend
app.get('/test', (req, res) => res.send('This is a test'))
app.get('/*', (req, res) => res.send('Not Found'))
//OR
app.get('/*', (req, res) => {
res.sendFile(__dirname, '/404.html');
})
app.listen(3000, () => console.log(`server up`))
//index.js on port 5500/frontend
document.addEventListener('DOMContentLoaded', function () {
fetch('http://localhost:3000/test)
.then(...)
})
now let’s say that it’s in the localhost:
frontend (index.html + index.js) are on http://127.0.0.1:5500/
backend (app.js) is on http://127.0.0.1:3000/
this working good if it requested from backend http://127.0.0.1:3000/ but if the request handled from the frontend (http://127.0.0.1:5500/NoExists ) it gets [Cannot GET /NoExists]
So, how to send a message {Not Found} to http://127.0.0.1:5500/NoExists?
in other words:
let app.js (backend) triggered by any request sent from index.js(frontend)
Use the response.status method
app.get('/*', (req, res) => res.status(404).send('Not Found'))
Edit: hopefully I understand the question now
You can leave the path blank to let it work for any undefined routes
app.get((req, res) => res.status(404).send('Not Found'));
// OR
app.get((req, res) => res.status(404).sendFile(__dirname, '/404.html'));
Edit 2: So from the video you sent, I think you want to display a 404 message in the front end.
Create a file in the same location as index.html and name it 404.html. This is just a normal html file, but its contents will be displayed when a page isn't found.
It looks like you're using live server, and I've found that the 404.html file doesn't work on live server, but it will work for most hosting services. Check this article or this one.

Angular JS and Node routing/wiring - data only showing after a page refresh

I'm using Node and Anugular, and I have created a RESTful api from my application, and created an angular resource to use this. I'm confused as to how the Angular ui-router directive reconciles with the Node Routing system on the server.
At the moment I have set up my routes/states in ui-router like this:
$stateProvier
.state('admin', {
url:'/admin',
templateUrl:'views/admin.html',
controller: 'adminController'
});
And this loads into the ui-view on my homepage, when I navigate to this url from a link on the loaded page.
HOWEVER, when I manually type in localhost/admin I get the route from Node, rather than the state render through angular.
Now I'd like to Angular to handle all the navigation on my app, and my resource to get the information, even if the address is typed manually into the navigation bar.
I've created a route in Node is for index, which contains my index.html page from angular, which effectively contains the whole app angular code, including all the routing.
My question is, how can I get angular redirect if I manually type the url into the address bar, and still have the data from the $resource.
I'm directing my resource to '/admin' - could this be the problem?
Does this mean that I need to add the contents of /routes/appointments' into the base node file (server.js), and then remove the route? If so then how do i direct my resource to the correct REST api?
app structure
public
-angular app
-app.js //for angular
routes
index.js
appointments.js
models
views
- index.ejs
server.js //node server file
here is my code exerpts
server.js
//standard routing code
var routes = require('./routes/index');
var appointments = require('./routes/appointments');
var app = express();
//configuring Express
app.set('port', process.env.PORT || 3000);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', __dirname + '/views');
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use('/', routes);
app.use('/', appointments);
routes/index.js
var express = require('express');
var router = express.Router();
// ./routes/index.js
router.get('/', function(req, res) {
res.render('index', { title: 'Homepage' });
});
module.exports = router;
routes/appointments.js - this is the basis of my RESTFUL api
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Todo = require('../models/Appointments.js');
/* GET /todos listing. */
router.get('/admin', function(req, res, next) {
Todo.find(function (err, todos) {
if (err) return next(err);
res.json(todos);
});
});
module.exports = router;
One way to do this is via the Accept header. If the request only accepts JSON then let the request go through to your API. If the request accepts HTML then always serve up your index page. Then once the index page loads angular's router will take care of the rest.
// Angular config - default Accept header for all ajax requests
$httpProvider.defaults.headers.common = {
'Accept': 'application/json'
};
// Middleware in Node to "intercept" non JSON requests
// Place this after express.static middleware but before your route definitions.
app.use(function(req, res, next) {
// keep in mind this applies to all requests, so 404s will need to be handled by your angular app since any url will serve up the index page
if(req.header('Accept') !== 'application/json') {
console.log('serving the index page');
req.url = '/'; // force the url to serve the index route.
}
next();
});
One more thing to note about this approach is that obviously you won't be able to see/debug your JSON data by hitting the URL directly anymore. There are several useful tools like Advanced REST Client or POSTman which actually give you better control and more options for things like that. Just make sure you set the Accept header in one of those tools and you'll be able to see the JSON response.
The actual URL is localhost#!/admin, try that. Angular hides the hashbang #!
Angular's URL routing is an "illusion" in that way. It only works on the client-side and only when your Angular app is loaded, which is on the main / route.
A solution could be to conditionally redirect from localhost/admin to localhost#!/admin, i.e. redirecting to your Angular app and passing it the #!/admin path. The condition could be a check for whether or not JSON was requested.
router.get('/admin', function(req, res, next) {
if(req.header('Accept') !== 'application/json')
return res.redirect('/#!/admin');
Todo.find(function (err, todos) {
if (err) return next(err);
res.json(todos);
});
});
You'll also need to configure Angular such that when it requests '/admin' json data from the server, it should only accept json (by setting the request header), which is how the the server will distinguish it from the regular '/admin' request. For that, if you're using $http.get you would do $http.get('/admin', {'Accept':'application/json'})

Handling routes with Angular and Express

I have an app where I am trying to remove the hashbang ( ! and #) prefixes for my routes, but still have people be able to use bookmarked routes. For the most part I have been able to get it work with html5Mode set to true, but there are a few cases where it is not working. Here is how I have my server configured:
var router = require('./router')(app);
app.use(express.static(path.join(__dirname, '../client')));
app.get('*', function (req, res, next) {
res.sendFile('index.html', {root:'../client/app/'});
});
router in this case looks like this:
var express = require('express');
var router = express.Router();
var Products = require('../../database').Products;
router.get('/:flavor', function (req, res) {
var flavor = req.params.flavor;
Products.findOne({flavor:flavor}, function (err, product) {
if (err) {
throw err
}
res.json(product);
});
Getting the flavor routes, is one case where this setup does not work. If someone directly types into the browse, mysite.com/lemon they receive the JSON data back, only (no template or anything). Normally this is used by the angular app, (which would typically make the request to /lemon and implement it into the template). However, if I move the router below the app.get('*'), then any request made by Angular for the data is returned with the entire index.html page. How can I make it so that a direct request by the browser for a route that normally returns JSON sends the index file?

Categories