Rate this docs

Angular Bootstrap file input

Angular File Input - Bootstrap 4 & Material Design

Angular Bootstrap file input is a field which user can use to upload one or more files (photos, documents or any other file type) from the local storage.

Standard file inputs usually leave a lot to wish for in terms of design, but MDB takes care of that by enhancing them with Material Design best practices.

Most common use examples:

  • CSV upload to CRM system
  • Avatar picture upload
  • Simple GIF upload

Below you can see a number of Angular Bootstrap file inputs created with Material Design for Bootstrap.


Basic example MDB Pro component

Choose file

        <form>
          <div class="file-field md-form">
            <div mdbBtn color="primary" size="sm" class="waves-light" mdbWavesEffect>
              <span>Choose file</span>
              <input type="file" mdbFileSelect (uploadOutput)="onUploadOutput($event)" [uploadInput]="uploadInput">
            </div>
            <div class="file-path-wrapper">
              <input class="file-path" type="text" placeholder="Upload your file" [value]="showFiles()">
            </div>
          </div>
          <button class="btn btn-md btn-primary" (click)="startUpload()">Start uploading</button>
        </form>
      

import { Component, EventEmitter } from '@angular/core';
import { UploadFile, UploadInput, UploadOutput } from 'ng-uikit-pro-standard';
import { humanizeBytes } from 'ng-uikit-pro-standard';

@Component({
selector: 'file-input-example',
templateUrl: 'file-input.html',
})

export class FileInputComponent  {
  formData: FormData;
  files: UploadFile[];
  uploadInput: EventEmitter<UploadInput>;
  humanizeBytes: Function;
  dragOver: boolean;

  constructor() {
      this.files = [];
      this.uploadInput = new EventEmitter<UploadInput>();
      this.humanizeBytes = humanizeBytes;
  }

  showFiles() {
      let files = '';
      for (let i = 0; i < this.files.length; i ++) {
        files += this.files[i].name;
         if (!(this.files.length - 1 === i)) {
           files += ',';
        }
      }
      return files;
   }

  startUpload(): void {
      const event: UploadInput = {
      type: 'uploadAll',
      url: 'your-path-to-backend-endpoint',
      method: 'POST',
      data: { foo: 'bar' },
      };
      this.files = [];
      this.uploadInput.emit(event);
  }

  cancelUpload(id: string): void {
      this.uploadInput.emit({ type: 'cancel', id: id });
  }

  onUploadOutput(output: UploadOutput | any): void {

      if (output.type === 'allAddedToQueue') {
      } else if (output.type === 'addedToQueue') {
        this.files.push(output.file); // add file to array when added
      } else if (output.type === 'uploading') {
        // update current data in files array for uploading file
        const index = this.files.findIndex(file => file.id === output.file.id);
        this.files[index] = output.file;
      } else if (output.type === 'removed') {
        // remove file from array when removed
        this.files = this.files.filter((file: UploadFile) => file !== output.file);
      } else if (output.type === 'dragOver') {
        this.dragOver = true;
      } else if (output.type === 'dragOut') {
      } else if (output.type === 'drop') {
        this.dragOver = false;
      }
      this.showFiles();
  }
}
      

File input with floating button MDB Pro component


          <form>
              <div class="file-field md-form">
                  <div mdbBtn floating="true" size="md" color="amber" mdbWavesEffect>
                    <i class="fa fa-cloud-upload" aria-hidden="true"></i>
                    <input type="file" mdbFileSelect (uploadOutput)="onUploadOutput($event)" [uploadInput]="uploadInput">
                  </div>
                <div class="file-path-wrapper mt-3">
                  <input class="file-path" type="text" placeholder="Upload your file" [value]="showFiles()">
                </div>
              </div>
              <button mdbBtn type="button" color="amber" class="waves-light" (click)="startUpload()" mdbWavesEffect>Start uploading</button>
        </form>
      

import { Component, EventEmitter } from '@angular/core';
import { UploadFile, UploadInput, UploadOutput } from 'ng-uikit-pro-standard';
import { humanizeBytes } from 'ng-uikit-pro-standard';

@Component({
selector: 'file-input-example',
templateUrl: 'file-input.html',
})

export class FileInputComponent  {
  formData: FormData;
  files: UploadFile[];
  uploadInput: EventEmitter<UploadInput>;
  humanizeBytes: Function;
  dragOver: boolean;

  constructor() {
      this.files = [];
      this.uploadInput = new EventEmitter<UploadInput>();
      this.humanizeBytes = humanizeBytes;
  }

  showFiles() {
      let files = '';
      for (let i = 0; i < this.files.length; i ++) {
        files += this.files[i].name;
         if (!(this.files.length - 1 === i)) {
           files += ',';
        }
      }
      return files;
   }

  startUpload(): void {
      const event: UploadInput = {
      type: 'uploadAll',
      url: 'your-path-to-backend-endpoint',
      method: 'POST',
      data: { foo: 'bar' },
      };
      this.files = [];
      this.uploadInput.emit(event);
  }

  cancelUpload(id: string): void {
      this.uploadInput.emit({ type: 'cancel', id: id });
  }

  onUploadOutput(output: UploadOutput | any): void {

      if (output.type === 'allAddedToQueue') {
      } else if (output.type === 'addedToQueue') {
        this.files.push(output.file); // add file to array when added
      } else if (output.type === 'uploading') {
        // update current data in files array for uploading file
        const index = this.files.findIndex(file => file.id === output.file.id);
        this.files[index] = output.file;
      } else if (output.type === 'removed') {
        // remove file from array when removed
        this.files = this.files.filter((file: UploadFile) => file !== output.file);
      } else if (output.type === 'dragOver') {
        this.dragOver = true;
      } else if (output.type === 'dragOut') {
      } else if (output.type === 'drop') {
        this.dragOver = false;
      }
      this.showFiles();
  }
}
      

File input with gradient floating button MDB Pro component


          <form>
              <div class="file-field md-form">
                  <div mdbBtn floating="true" size="md" gradient="purple" mdbWavesEffect>
                    <i class="fa fa-cloud-upload" aria-hidden="true"></i>
                    <input type="file" mdbFileSelect (uploadOutput)="onUploadOutput($event)" [uploadInput]="uploadInput">
                  </div>
                <div class="file-path-wrapper mt-3">
                  <input class="file-path" type="text" placeholder="Upload your file" [value]="showFiles()">
                </div>
              </div>
              <button mdbBtn type="button" gradient="purple" class="waves-light" (click)="startUpload()" mdbWavesEffect>Start uploading</button>
        </form>
      

import { Component, EventEmitter } from '@angular/core';
import { UploadFile, UploadInput, UploadOutput } from 'ng-uikit-pro-standard';
import { humanizeBytes } from 'ng-uikit-pro-standard';

@Component({
selector: 'file-input-example',
templateUrl: 'file-input.html',
})

export class FileInputComponent  {
  formData: FormData;
  files: UploadFile[];
  uploadInput: EventEmitter<UploadInput>;
  humanizeBytes: Function;
  dragOver: boolean;

  constructor() {
      this.files = [];
      this.uploadInput = new EventEmitter<UploadInput>();
      this.humanizeBytes = humanizeBytes;
  }

  showFiles() {
      let files = '';
      for (let i = 0; i < this.files.length; i ++) {
        files += this.files[i].name;
         if (!(this.files.length - 1 === i)) {
           files += ',';
        }
      }
      return files;
   }

  startUpload(): void {
      const event: UploadInput = {
      type: 'uploadAll',
      url: 'your-path-to-backend-endpoint',
      method: 'POST',
      data: { foo: 'bar' },
      };
      this.files = [];
      this.uploadInput.emit(event);
  }

  cancelUpload(id: string): void {
      this.uploadInput.emit({ type: 'cancel', id: id });
  }

  onUploadOutput(output: UploadOutput | any): void {

      if (output.type === 'allAddedToQueue') {
      } else if (output.type === 'addedToQueue') {
        this.files.push(output.file); // add file to array when added
      } else if (output.type === 'uploading') {
        // update current data in files array for uploading file
        const index = this.files.findIndex(file => file.id === output.file.id);
        this.files[index] = output.file;
      } else if (output.type === 'removed') {
        // remove file from array when removed
        this.files = this.files.filter((file: UploadFile) => file !== output.file);
      } else if (output.type === 'dragOver') {
        this.dragOver = true;
      } else if (output.type === 'dragOut') {
      } else if (output.type === 'drop') {
        this.dragOver = false;
      }
      this.showFiles();
  }
}
      

File input with rounded outline button MDB Pro component


          <form>
              <div class="file-field md-form">
                  <div mdbBtn rounded="true" outline="true" color="secondary" size="md" mdbWavesEffect>
                    <span class="pt-1">Choose file</span>
                    <input type="file" mdbFileSelect (uploadOutput)="onUploadOutput($event)" [uploadInput]="uploadInput">
                  </div>
                <div class="file-path-wrapper mt-2">
                  <input class="file-path" type="text" placeholder="Upload your file" [value]="showFiles()">
                </div>
              </div>
              <button mdbBtn type="button" rounded="true" outline="true" color="secondary" (click)="startUpload()" mdbWavesEffect>Start uploading</button>
        </form>
      

import { Component, EventEmitter } from '@angular/core';
import { UploadFile, UploadInput, UploadOutput } from 'ng-uikit-pro-standard';
import { humanizeBytes } from 'ng-uikit-pro-standard';

@Component({
selector: 'file-input-example',
templateUrl: 'file-input.html',
})

export class FileInputComponent  {
  formData: FormData;
  files: UploadFile[];
  uploadInput: EventEmitter<UploadInput>;
  humanizeBytes: Function;
  dragOver: boolean;

  constructor() {
      this.files = [];
      this.uploadInput = new EventEmitter<UploadInput>();
      this.humanizeBytes = humanizeBytes;
  }

  showFiles() {
      let files = '';
      for (let i = 0; i < this.files.length; i ++) {
        files += this.files[i].name;
         if (!(this.files.length - 1 === i)) {
           files += ',';
        }
      }
      return files;
   }

  startUpload(): void {
      const event: UploadInput = {
      type: 'uploadAll',
      url: 'your-path-to-backend-endpoint',
      method: 'POST',
      data: { foo: 'bar' },
      };
      this.files = [];
      this.uploadInput.emit(event);
  }

  cancelUpload(id: string): void {
      this.uploadInput.emit({ type: 'cancel', id: id });
  }

  onUploadOutput(output: UploadOutput | any): void {

      if (output.type === 'allAddedToQueue') {
      } else if (output.type === 'addedToQueue') {
        this.files.push(output.file); // add file to array when added
      } else if (output.type === 'uploading') {
        // update current data in files array for uploading file
        const index = this.files.findIndex(file => file.id === output.file.id);
        this.files[index] = output.file;
      } else if (output.type === 'removed') {
        // remove file from array when removed
        this.files = this.files.filter((file: UploadFile) => file !== output.file);
      } else if (output.type === 'dragOver') {
        this.dragOver = true;
      } else if (output.type === 'dragOut') {
      } else if (output.type === 'drop') {
        this.dragOver = false;
      }
      this.showFiles();
  }
}
      

File input with rounded gradient button MDB Pro component


          <form>
              <div class="file-field md-form">
                  <div mdbBtn rounded="true" gradient="aqua" size="md" mdbWavesEffect>
                    <span class="pt-1">Choose file</span>
                    <input type="file" mdbFileSelect (uploadOutput)="onUploadOutput($event)" [uploadInput]="uploadInput">
                  </div>
                <div class="file-path-wrapper mt-2">
                  <input class="file-path" type="text" placeholder="Upload your file" [value]="showFiles()">
                </div>
              </div>
              <button mdbBtn type="button" rounded="true" gradient="aqua" (click)="startUpload()" mdbWavesEffect>Start uploading</button>
        </form>
      

import { Component, EventEmitter } from '@angular/core';
import { UploadFile, UploadInput, UploadOutput } from 'ng-uikit-pro-standard';
import { humanizeBytes } from 'ng-uikit-pro-standard';

@Component({
selector: 'file-input-example',
templateUrl: 'file-input.html',
})

export class FileInputComponent  {
  formData: FormData;
  files: UploadFile[];
  uploadInput: EventEmitter<UploadInput>;
  humanizeBytes: Function;
  dragOver: boolean;

  constructor() {
      this.files = [];
      this.uploadInput = new EventEmitter<UploadInput>();
      this.humanizeBytes = humanizeBytes;
  }

  showFiles() {
      let files = '';
      for (let i = 0; i < this.files.length; i ++) {
        files += this.files[i].name;
         if (!(this.files.length - 1 === i)) {
           files += ',';
        }
      }
      return files;
   }

  startUpload(): void {
      const event: UploadInput = {
      type: 'uploadAll',
      url: 'your-path-to-backend-endpoint',
      method: 'POST',
      data: { foo: 'bar' },
      };
      this.files = [];
      this.uploadInput.emit(event);
  }

  cancelUpload(id: string): void {
      this.uploadInput.emit({ type: 'cancel', id: id });
  }

  onUploadOutput(output: UploadOutput | any): void {

      if (output.type === 'allAddedToQueue') {
      } else if (output.type === 'addedToQueue') {
        this.files.push(output.file); // add file to array when added
      } else if (output.type === 'uploading') {
        // update current data in files array for uploading file
        const index = this.files.findIndex(file => file.id === output.file.id);
        this.files[index] = output.file;
      } else if (output.type === 'removed') {
        // remove file from array when removed
        this.files = this.files.filter((file: UploadFile) => file !== output.file);
      } else if (output.type === 'dragOver') {
        this.dragOver = true;
      } else if (output.type === 'dragOut') {
      } else if (output.type === 'drop') {
        this.dragOver = false;
      }
      this.showFiles();
  }
}
      

Angular File Input - API

In this section you will find informations about required modules of file input component.


Modules used

In order to speed up your application, you can choose to import only the modules you actually need, instead of importing the entire MDB Angular library. Remember that importing the entire library, and immediately afterwards a specific module, is bad practice, and can cause application errors.

// MDB Angular Pro
import { FileInputModule, WavesModule } from 'ng-uikit-pro-standard'

Angular File Input - examples & customization


Uploading file with File Input MDB Pro component

In order to show how to send a file through the File Input component, you need to set up a server. We will use Node + Express.js stack.

If you come across a problem, please check our support forum to see if someone else has already had a similar problem. If not, then feel free to set up a new topic!

The whole project is available at this address as a zip archive.

As a first step, copy the following HTML and TS code into your project.



        <form>
          <div class="file-field md-form d-flex justify-content-between align-items-center">
            <div mdbBtn floating="true" size="md" color="amber" mdbWavesEffect>
              <i class="fa fa-cloud-upload" aria-hidden="true"></i>
              <input type="file" mdbFileSelect (uploadOutput)="onUploadOutput($event)" [uploadInput]="uploadInput">
            </div>
            <div class="file-path-wrapper mt-1">
              <input class="file-path" type="text" placeholder="Upload your file" [value]="showFiles()">
            </div>
            <button mdbBtn type="button" size="sm" color="amber" rounded="true" class="darken-2 waves-light" (click)="startUpload()"
              mdbWavesEffect>Start
              uploading</button>
          </div>
        </form>

      

            import { Component, EventEmitter } from '@angular/core';
            import { UploadInput, UploadOutput, UploadFile, humanizeBytes } from 'ng-uikit-pro-standard';

            @Component({
              selector: 'app-root',
              templateUrl: './app.component.html',
              styleUrls: ['./app.component.scss']
            })
            export class AppComponent {
              formData: FormData;
              files: UploadFile[];
              uploadInput: EventEmitter<UploadInput>;
              humanizeBytes: Function;
              dragOver: boolean;

              constructor() {
                  this.files = [];
                  this.uploadInput = new EventEmitter<UploadInput>();
                  this.humanizeBytes = humanizeBytes;
              }

              showFiles() {
                  let files = '';
                  for (let i = 0; i < this.files.length; i ++) {
                    files += this.files[i].name;
                     if (!(this.files.length - 1 === i)) {
                       files += ',';
                    }
                  }
                  return files;
               }

              startUpload(): void {
                  const event: UploadInput = {
                  type: 'uploadAll',
                  url: 'http://localhost:3001/api/upload',
                  method: 'POST',
                  data: { foo: 'bar' },
                  };
                  this.files = [];
                  this.uploadInput.emit(event);
              }

              cancelUpload(id: string): void {
                  this.uploadInput.emit({ type: 'cancel', id: id });
              }

              onUploadOutput(output: UploadOutput | any): void {
                  if (output.type === 'allAddedToQueue') {
                  } else if (output.type === 'addedToQueue') {
                    this.files.push(output.file); // add file to array when added
                  } else if (output.type === 'uploading') {
                    // update current data in files array for uploading file
                    const index = this.files.findIndex(file => file.id === output.file.id);
                    this.files[index] = output.file;
                  } else if (output.type === 'removed') {
                    // remove file from array when removed
                    this.files = this.files.filter((file: UploadFile) => file !== output.file);
                  } else if (output.type === 'dragOver') {
                    this.dragOver = true;
                  } else if (output.type === 'dragOut') {
                  } else if (output.type === 'drop') {
                    this.dragOver = false;
                  }
                  this.showFiles();
              }
            }
      

Necessary files and folders

In the next step in your application's root directory, create the following folders and the files that they will contain.

  • bin/www.ts,
  • routes/index.ts,
  • uploads,
  • app.ts.
File upload files structure

Necessary libraries and filling up files

The next step is to install the following additional libraries, thanks to which we will handle the sending of the file to the backend, and then complete the previously created files with the required code.


      npm install --save express body-parser cors multer
    

Copy the below code into app.ts file


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

      const indexRouter = require('./routes/index');
      const app = express();

      const corsOptions = {
        origin: '*',
        optionsSuccessStatus: 200
      };

      app.use(cors(corsOptions));
      app.use(bodyParser.json());
      app.use(bodyParser.urlencoded({ extended: true }));

      // create a cors middleware
      app.use((req, res, next) => {
        // set headers to allow cross origin request.
        res.header('Access-Control-Allow-Origin', '*');
        res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
        res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
        next();
      });

      app.use('/api', indexRouter);

      module.exports = app;

    

Then copy the below code into routes/index.ts file


      const exp = require('express');
      const router = exp.Router();
      const multer = require('multer');
      const DIR = './uploads/';

      let upload = multer({ dest: DIR }).single('file');

      router.post('/upload', (req, res, next) => {
        let path = '';
        upload(req, res, (err) => {
            if (err) {
                console.log(err);
                return res.status(422).send('An error occured');
            }
            path = req.file.path;
            console.log('Uploaded');
            return res.send('Upload completed for ' + path);
        });
      });
      module.exports = router;

    

And the last .ts file which you have to fill up is bin/www.ts file.


      #!/usr/bin/env node

      /**
      * Module dependencies.
      */

      const appFile = require('../app');
      const debug = require('debug')('file-upload:server');
      const http = require('http');

      /**
      * Get port from environment and store in Express.
      */

      const port = normalizePort(process.env.PORT || '3001');
      appFile.set('port', port);

      /**
      * Create HTTP server.
      */

      const server = http.createServer(appFile);

      /**
      * Listen on provided port, on all network interfaces.
      */

      server.listen(port);
      server.on('error', onError);
      server.on('listening', onListening);

      /**
      * Normalize a port into a number, string, or false.
      */

      function normalizePort(val) {
        const portNumber = parseInt(val, 10);

        if (isNaN(portNumber)) {
        // named pipe
        return val;
        }

        if (portNumber >= 0) {
        // port number
        return portNumber;
        }

        return false;
      }

      /**
      * Event listener for HTTP server "error" event.
      */

      function onError(error) {
      if (error.syscall !== 'listen') {
        throw error;
      }

      const bind = typeof port === 'string' ?
      'Pipe ' + port :
      'Port ' + port;

      // handle specific listen errors with friendly messages
      switch (error.code) {
        case 'EACCES':
        console.error(bind + ' requires elevated privileges');
        process.exit(1);
        break;
        case 'EADDRINUSE':
        console.error(bind + ' is already in use');
        process.exit(1);
        break;
        default:
        throw error;
      }
      }

      /**
      * Event listener for HTTP server "listening" event.
      */

      function onListening() {
        const addr = server.address();
        const bind = typeof addr === 'string' ?
        'pipe ' + addr :
        'port ' + addr.port;
        debug('Listening on ' + bind);
      }

    

After you have completed all required files with the above code, add a script to the package.json file, which will run your server.


      "server": "tsc app.ts && tsc routes/index.ts && tsc bin/www.ts && node ./bin/www.js"
    

Running the server and testing file upload

At the very end, we have nothing left to do but to run the server and the application. To do this, open two terminal windows, and run the commands npm run server and ng serve in them.


      npm run server
    

      ng serve
    

Conclusion

The above commands will run two processes - one responsible for server operation and the other for Angular application operation. Now it is enough to select a file and press the Upload button, and after a while, this file will be in your project, in the uploads directory. The name of this file is hashed, so you can avoid duplicate files.

Important note

Please note that a piece of CORS-enabled code is only placed in the development environment. It is not recommended to use this piece of code in a production environment unless you know what you are doing.