0

I'm using NodeJS server to gather data from a MySQL database, and returning it as a JSON object.

  app.get('/random', (req, res) => {
  var connection = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: '',
    database: 'test'
  });
  connection.connect((err) => {
    if(err) {
      res.send(err);
    } else {
      console.log("Connected to database!");
      connection.query("SELECT * FROM test", (err, rows) => {
        if(err) {
          res.send(err);
        } else {
          res.json(rows);
        }
      })
    }
  });
})

Entering the URL manually (localhost:3000/random) causes the JSON object to render, which is not what I want.

However, using Angular (v4) routing, it renders the HTML as I want it, which is with the header, footer and the data inbetween. Important angular code can be seen below.

random.service.ts

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';

@Injectable()
export class RandomService {
  constructor(private http: Http) {
    console.log('Random service initialized!');
  }

  fetchData() {
    return this.http.get('/random')
    .map(res => res.json());
  }
}

random.component.ts

import { Component, OnInit } from '@angular/core';
import { RandomService } from './random.service';
import { Random } from '../../../Random';

@Component({
  selector: 'app-random',
  templateUrl: './random.component.html',
  styleUrls: ['./random.component.css'],
  providers: [RandomService]
})
export class RandomComponent implements OnInit {

  random: Random[];

  constructor(private randomService: RandomService) {
    this.randomService.fetchData()
    .subscribe(data => {
      this.random = data;
    })
  }

  ngOnInit() {
  }

}

random.component.html

<h1>Random</h1>
<div *ngFor="let r of random">
  ID: {{ r.idtest }}
  <br>
  Column: {{ r.testcol }}
  <br>
</div>

app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component';
import { HomeComponent } from './components/home/home.component';
import { RandomComponent } from './components/random/random.component';

const appRoutes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'random', component: RandomComponent },
  { path: 'page-not-found', component: PageNotFoundComponent },
  { path: '**', component: PageNotFoundComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(appRoutes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

app.component.html

<app-header></app-header>
<router-outlet></router-outlet>
<app-footer></app-footer>

I know the issue, which is I never try to render the Angular component through the server. I've tried researching, but I can't seem to find out how to do this.

TL;DR: Can't figure out how to render Angular component using NodeJS, or figure out another way around.

My issue shown in pictures:

Accessing the random-page using routing through Angular Angular routing

Accessing the random-page by manually entering the URL (or refreshing random-page) Entering URL manually

user3510657
  • 77
  • 1
  • 8

2 Answers2

1

The URL of angular and the node API much differ both are /random

when you directly hit the URL then the node server will serve the route accordingly.

in your case change the name of the API URL. The general convention is to prefix with the /api/{name} for all of your Node.js API's in this way to can avoid such issues

nmanikiran
  • 2,866
  • 15
  • 19
1

All routes should be handled by serving index.html. A common practice is mounting your json api to a prefix like /api/random. So, if you visit localhost:3000/random, your backend should serve index.html. Then, your angular application should make an api call to localhost:3000/api/random to retrieve dynamic data.

This can be done with express standalone:

index.js

const express = require('express');
const api = require('./api.js')
const app = express();
app.use('/public', express.static(__dirname + '/public'));
app.use('/api', api) // Very important. mount your api before the all path '/*' catch 
app.get('/*', function(req, res){
  res.sendFile(__dirname + '/index.html');
});

app.listen(8000)

api.js

const express = require('express')
const router = express.Router()
router.get('/random' /*your random api handler*/)
module.exports = router

Another (better) approch would be using a frontend http server/load balancer like NGINX in front of your nodejs api server.. Look here

OUT: Another thing: you should connnect to your database only one time, usually just before http server bootstrap. Then you should export your connection object and use it inside your api logic. Making a connection to a database for each request will overkill your app.

EDIT: with this pattern (it doesn't matter if with express standalone or with nginx), your SPA frontend (in your case built with angular) has the responsability to handle 404 status page.

Community
  • 1
  • 1
radar155
  • 1,796
  • 2
  • 11
  • 28