Serving static content alongisde Angular app

I want to server some static content on the root of my web server (landing page) alongside an angular app. I want to be able to serve the static content when the user accesses the '/' (root) of the page while service the app at '/portal'.

I want to server some static content on the root of my web server (landing page) alongside an angular app. I want to be able to serve the static content when the user accesses the '/' (root) of the page while service the app at '/portal'.

I've tried making the static content individual components, but since I'm working with a predefined template I cannot include them (I get parse errors at compile-time, because of duplicate <doctype>, etc etc).

Also, I'm serving the whole thing with express, so what I thought of was to make use of express' utilities

app.use('/',express.static(path.join(__dirname, 'dist/landing')));
app.use('/portal',express.static(path.join(__dirname, 'dist')));

so far I got the landing page working, and I'm able to access the prtal part but I see on the console that the resources (vendor.js, runtime.js etc) are not being loaded (404s).

Other combinations of app.use and app.get might get me to the point of accessing the portal and have it working but whenever I refresh the page inside it (I'm logged in) I get a blan page (404).

I have the <base> set to href='/' but changing it has only complicated things more.

I'm sorry to be asking this, but I'm a complete newbie on angular/express. Is there a way to get around this? I haven't been able to find an example that covers serving static files and an app using express

Would someone please guide me through this? I tried every combination of app.use and app.getand read lots of documentation without getting a clear understanding of how this would work.

Thanks in advance.

Angular 8 Node & Express JS File Upload

Angular 8 Node & Express JS File Upload

In this Angular 8 and Node.js tutorial, we are going to look at how to upload files on the Node server. To create Angular image upload component, we will be using Angular 8 front-end framework along with ng2-file-upload NPM package; It’s an easy to use Angular directives for uploading the files.

In this Angular 8 and Node.js tutorial, we are going to look at how to upload files on the Node server. To create Angular image upload component, we will be using Angular 8 front-end framework along with ng2-file-upload NPM package; It’s an easy to use Angular directives for uploading the files.

We are also going to take the help of Node.js to create the backend server for Image or File uploading demo. Initially, we’ll set up an Angular 8 web app from scratch using Angular CLI. You must have Node.js and Angular CLI installed in your system.

We’ll create the local server using Node.js and multer middleware. Multer is a node.js middleware for handling multipart/form-data, which is primarily used for uploading files. Once we are done setting up front-end and backend for our File uploading demo then, we’ll understand step by step how to configure file uploading in Angular 8 app using Node server.

Prerequisite

In order to show you Angular 8 File upload demo, you must have Node.js and Angular CLI installed in your system. If not then check out this tutorial: Set up Node JS

Run following command to install Angular CLI:

npm install @angular/cli -g

Install Angular 8 App

Run command to install Angular 8 project:

ng new angular-node-file-upload

# ? Would you like to add Angular routing? No
# ? Which stylesheet format would you like to use? CSS
cd angular-node-file-upload

Show Alert Messages When File Uploaded

We are going to install and configure ngx-toastr an NPM package which helps in showing the alert message when the file is uploaded on the node server.

npm install ngx-toastr --save

The ngx-toastr NPM module requires @angular/animations dependency:

npm install @angular/animations --save

Then, add the ngx-toastr CSS in angular.json file:

"styles": [
    "src/styles.css",
    "node_modules/ngx-toastr/toastr.css"
]

Import BrowserAnimationsModule and ToastrModule in app.module.ts file:

import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ToastrModule } from 'ngx-toastr';
 
@NgModule({
  imports: [
    CommonModule,
    BrowserAnimationsModule, // required animations module
    ToastrModule.forRoot() // ToastrModule added
  ]
})

export class AppModule { }

Install & Configure ng-file-upload Directive

In this step, we’ll Install and configure ng-file-upload library in Angular 8 app. Run command to install ng-file-upload library.

npm install ng2-file-upload

Once the ng2-file-upload directive is installed, then import the FileSelectDirective and FormsModule in app.module.ts. We need FormsModule service so that we can create the file uploading component in Angular.

import { FileSelectDirective } from 'ng2-file-upload';
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    FileSelectDirective
  ],
  imports: [
    FormsModule
  ]
})

export class AppModule { }

Setting Up Node Backend for File Upload Demo

To upload the file on the server, we need to set up a separate backend. In this tutorial, we will be using Node & Express js to create server locally along with multer, express js, body-parser, and dotenv libraries.

Run command to create backend folder in Angular app’s root directory:

mkdir backend && cd backend

In the next step, create a specific package.json file.

npm init

Run command to install required dependencies:

npm install express cors body-parser multer dotenv --save

In order to get rid from starting the server again and again, install nodemon NPM package. Use –-save-dev along with the npm command to register in the devDependencies array. It will make it available for development purpose only.

npm install nodemon --save-dev

Have a look at final pacakge.json file for file upload demo backend:

{
  "name": "angular-node-file-upload",
  "version": "1.0.0",
  "description": "Angualr 8 file upload demo app",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js"
  },
  "author": "Digamber Rawat",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.19.0",
    "cors": "^2.8.5",
    "dotenv": "^8.0.0",
    "express": "^4.17.1",
    "multer": "^1.4.1"
  },
  "devDependencies": {
    "nodemon": "^1.19.1"
  }
}

Create a file by the name of server.js inside backend folder:

Configure Server.js

To configure our backend we need to create a server.js file. In this file we’ll keep our backend server’s settings.

touch server.js

Now, paste the following code in backend > server.js file:

const express = require('express'),
  path = require('path'),
  cors = require('cors'),
  multer = require('multer'),
  bodyParser = require('body-parser');

// File upload settings  
const PATH = './uploads';

let storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, PATH);
  },
  filename: (req, file, cb) => {
    cb(null, file.fieldname + '-' + Date.now())
  }
});

let upload = multer({
  storage: storage
});

// Express settings
const app = express();
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
  extended: false
}));

app.get('/api', function (req, res) {
  res.end('File catcher');
});

// POST File
app.post('/api/upload', upload.single('image'), function (req, res) {
  if (!req.file) {
    console.log("No file is available!");
    return res.send({
      success: false
    });

  } else {
    console.log('File is available!');
    return res.send({
      success: true
    })
  }
});

// Create PORT
const PORT = process.env.PORT || 8080;
const server = app.listen(PORT, () => {
  console.log('Connected to port ' + PORT)
})

// Find 404 and hand over to error handler
app.use((req, res, next) => {
  next(createError(404));
});

// error handler
app.use(function (err, req, res, next) {
  console.error(err.message);
  if (!err.statusCode) err.statusCode = 500;
  res.status(err.statusCode).send(err.message);
});

Now, while staying in the backend folder run the below command to start the backend server:

nodemon server.js

If everything goes fine then you’ll get the following output:

[nodemon] 1.19.1
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node server.js`
Connected to port 8080

Create Angular 8 File Upload Component

In this last step, we are going to create a file upload component in Angular 8 app using Express js API.

Get into the app.component.ts file and include the following code:

import { Component, OnInit } from '@angular/core';
import { FileUploader } from 'ng2-file-upload/ng2-file-upload';
import { ToastrService } from 'ngx-toastr';

const URL = 'http://localhost:8080/api/upload';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent implements OnInit {
  public uploader: FileUploader = new FileUploader({
    url: URL,
    itemAlias: 'image'
  });

  constructor(private toastr: ToastrService) { }

  ngOnInit() {
    this.uploader.onAfterAddingFile = (file) => {
      file.withCredentials = false;
    };
    this.uploader.onCompleteItem = (item: any, status: any) => {
      console.log('Uploaded File Details:', item);
      this.toastr.success('File successfully uploaded!');
    };
  }

}

Go to app.component.html file and add the given below code:

<div class="wrapper">
  <h2>Angular Image Upload Demo</h2>

  <div class="file-upload">
    <input type="file" name="image" ng2FileSelect [uploader]="uploader" accept="image/x-png,image/gif,image/jpeg" />
    <button type="button" (click)="uploader.uploadAll()" [disabled]="!uploader.getNotUploadedItems().length">
      Upload
    </button>
  </div>

</div>

Now, It’s time to start the Angular 8 app to check out the File upload demo in the browser. Run the following command:

ng serve --open

Make sure your NODE server must be running to manage the backend.

When you upload the image from front-end you’ll see your image files are saving inside the backend > uploads folder.

Conclusion

In this Angular 8 tutorial, we barely scratched the surface related to file uploading in a Node application. There are various other methods available on the internet through which you can achieve file uploading task quickly. However, this tutorial is suitable for beginners developers. I hope this tutorial will surely help and you if you liked this tutorial, please consider sharing it with others.

Angular + WebSocket + Node.js Express = RxJS WebSocketSubject ❤️

Angular + WebSocket + Node.js Express = RxJS WebSocketSubject ❤️

I this article, you'll learn how to create an Angular client using RxJS WebSocketSubject, WebSocket, Node.js and Express.js

I this article, you'll learn how to create an Angular client using RxJS WebSocketSubject, WebSocket, Node.js and Express.js

Given the wide interest in my previous article on WebSocket, Node and Express (thanks to everyone 😅) I created a simple Angular client that allows you to communicate with the server made in the previous tutorial (PS: I also updated the libraries related to the server component 🎉).

This mini-project (source code here and working DEMO here**🎠 **— try to open two or more browser windows and play with the broadcast button) can be summarized in the following code snippet:

import { Component, ViewChild, ElementRef, OnInit, AfterViewInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { WebSocketSubject } from 'rxjs/observable/dom/WebSocketSubject';

export class Message {
    constructor(
        public sender: string,
        public content: string,
        public isBroadcast = false,
    ) { }
}

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit {

    //...

    private socket$: WebSocketSubject<Message>;

    constructor() {
        this.socket$ = WebSocketSubject.create('ws://localhost:8999');

        this.socket$
            .subscribe(
            (message) => this.serverMessages.push(message) && this.scroll(),
            (err) => console.error(err),
            () => console.warn('Completed!')
            );
    }

    //...
}

websocket-node-express-component.ts hosted with ❤ by GitHub

As you can see, we are initializing a WebSocketSubject and specifying the type of object we intend to obtain from the server (in this case, simply a Message).

Obviously, the definition of the obtained object must conform to what is communicated by the server (for this reason I always suggest working with shared objects inside your repo— in this case we are facilitated by using both server and client side of the same language, Typescript 😎).

Coming back to the definition of the WebSocketSubject we can say that this is a very useful tool of RxJS library that represents a wrapper around the w3c-compatible WebSocket object provided by the browser.

It is therefore sufficient to subscribe and define the actions that our code must perform:

  • upon obtaining new values, the new message will be added to an array, providing the scroll of the interface in order to display it properly
  • receiving an error it will be displayed in the console
  • at the end of the stream a warning will be presented in the console

The rest of the client shows a little graphic trick to make the scroll of the interface a little bit smooth without using any additional library 😏. If you want, checkout the animation algorithm at 60fps with the calculation of the remaining scroll.

You could get the same thing with the CSS only but I preferred to get my hands dirty to refresh the characteristics of the @ViewChild and ElementRef).

 private getDiff(): number {
        const nativeElement = this.viewer.nativeElement;
        return nativeElement.scrollHeight - (nativeElement.scrollTop + nativeElement.clientHeight);
    }

    private scrollToBottom(t = 1, b = 0): void {
        if (b < 1) {
            b = this.getDiff();
        }
        if (b > 0 && t <= 120) {
            setTimeout(() => {
                const diff = this.easeInOutSin(t / 120) * this.getDiff();
                this.viewer.nativeElement.scrollTop += diff;
                this.scrollToBottom(++t, b);
            }, 1 / 60);
        }
    }

    private easeInOutSin(t): number {
        return (1 + Math.sin(Math.PI * t - Math.PI / 2)) / 2;
}

websocket-node-express-component-scroll.ts hosted with ❤ by GitHub

The same applies to the calculation of the badge color based on the initials typed by the user ;)

 public getSenderInitials(sender: string): string {
        return sender && sender.substring(0, 2).toLocaleUpperCase();
    }

    private getSenderColor(sender: string): string {
        const alpha = '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZ';
        const initials = this.getSenderInitials(sender);
        const value = Math.ceil((alpha.indexOf(initials[0]) + alpha.indexOf(initials[1])) * 255 * 255 * 255 / 70);
        return '#' + value.toString(16).padEnd(6, '0');
}

websocket-node-express-component-initials-color.ts hosted with ❤ by GitHub

For demonstration purposes only, within the server I added a 1000ms timeout to make the server response more “real” in case you want to try the compiled code locally.

Conclusions

In just a few steps, we’ve created an Angular client using RxJS WebSocketSubject: soon we can go deep in catching errors and reconnection policies, but this will come in another story 🎉