Athwart xiii drag and drop file upload tutorial; In this article; we will learn to upload multiple prototype files in MongoDB database using Node and Express.

In this tutorial we volition create a basic Angular app in which we will utilise to create a custom directive to build Angular elevate and drib functionality.

Tutorial Objective

  • Building Angular drag and drib file uploading Layout with HTML/CSS
  • Creating a Node server to upload prototype files
  • Creating Custom Drag and Drib directive
  • Using Multer for Multiple file uploading
  • Multiple files uploading with progress bar

Angular xiii Elevate and Drop File Uploading Example

  • Install Angular App
  • Build Node/Express Server
  • Build File Upload Rest API with Multer & Express
  • Configure Node/Express Server
  • Create Angular Drag and Driblet File Uploading Directive
  • Create Angular Service
  • Create Drag and Drib File Upload Component

Install Athwart App

Permit'due south start by installing basic Angular app, run the following command:

                  ng new angular-dragdrop-fileupload                

So, navigate to the newly created Angular project:

                                      cd                    angular-dragdrop-fileupload                

Next, create Angular component for elevate and driblet file upload.

                  ng m c drag-drop                

Side by side, run command to install Bootstrap.

                  npm install bootstrap                

Add the Bootstrap CSS in package.json file.

                                      "styles"                    :                    [                    "node_modules/bootstrap/dist/css/bootstrap.min.css"                    ,                    "src/styles.scss"                    ]                                  

Build Node/Express Server

Build a node server with express js to store the uploaded files on the MongoDB database. We will apply Multer to store the image files along with other NPM packages.

Run the command from Angular project'south root to generate backend binder:

                                      mkdir                    backend                    &&                    cd                    backend                

Create separate package.json for node server.

                                      npm                    init                

Run control to install required NPM packages.

                                      npm                    install                    body-parser cors express mongoose multer --relieve                

Also, install nodemon NPM module, it starts the server whenever any change occurs in server code.

                                      npm                    install                    nodemon --save-dev                

Ascertain Mongoose Schema

Create models binder inside the backend directory, and then create a file User.js and place the following code inside of it.

                                      const                    mongoose                    =                    require                    (                    'mongoose'                    )                    ;                    const                    Schema                    =                    mongoose.Schema;                    // Define Schema                    let                    userSchema                    =                    new                    Schema                    (                    {                    _id:                    mongoose.Schema.Types.ObjectId,                    avatar:                    {                    blazon:                    Assortment                    }                    ,                    }                    ,                    {                    collection:                    'users'                    }                    )                    module.exports                    =                    mongoose.                    model                    (                    'User'                    ,                    userSchema)                                  

Build File Upload Rest API with Multer & Express

Let's first create a folder and name it public inside the backend folder. Hither, in this binder where we will store all the uploaded files.

Run the command from the backend folder's root.

                                      mkdir                    public                

Create a routes folder inside the backend folder. Create a file user.routes.js inside of it. Here we sick import express, multer and mongoose NPM modules. By using these services nosotros volition build REST API for storing multiple files in MongoDB database.

Add the given beneath code inside the user.routes.js.

                                      permit                    express                    =                    require                    (                    'express'                    )                    ,                    multer                    =                    require                    (                    'multer'                    )                    ,                    mongoose                    =                    require                    (                    'mongoose'                    )                    ,                    router                    =                    limited.                    Router                    (                    )                    ;                    // Multer File upload settings                    const                    DIR                    =                    './public/'                    ;                    const                    storage                    =                    multer.                    diskStorage                    (                    {                    destination                    :                    (                    req,                      file,                      cb                    )                    =>                    {                    cb                    (                    nada                    ,                    DIR                    )                    ;                    }                    ,                    filename                    :                    (                    req,                      file,                      cb                    )                    =>                    {                    const                    fileName                    =                    file.originalname.                    toLowerCase                    (                    )                    .                    split up                    (                    ' '                    )                    .                    join                    (                    '-'                    )                    ;                    cb                    (                    null                    ,                    fileName)                    }                    }                    )                    ;                    var                    upload                    =                    multer                    (                    {                    storage:                    storage,                    // limits: {                    //   fileSize: 1024 * 1024 * five                    // },                    fileFilter                    :                    (                    req,                      file,                      cb                    )                    =>                    {                    if                    (file.mimetype                    ==                    "image/png"                    ||                    file.mimetype                    ==                    "epitome/jpg"                    ||                    file.mimetype                    ==                    "image/jpeg"                    )                    {                    cb                    (                    cypher                    ,                    true                    )                    ;                    }                    else                    {                    cb                    (                    nothing                    ,                    imitation                    )                    ;                    return                    cb                    (                    new                    Error                    (                    'Only .png, .jpg and .jpeg format allowed!'                    )                    )                    ;                    }                    }                    }                    )                    ;                    // User model                    permit                    User                    =                    require                    (                    '../models/User'                    )                    ;                    router.                    mail service                    (                    '/create-user'                    ,                    upload.                    assortment                    (                    'avatar'                    ,                    6                    )                    ,                    (                    req,                      res,                      next                    )                    =>                    {                    const                    reqFiles                    =                    [                    ]                    const                    url                    =                    req.protocol                    +                    '://'                    +                    req.                    go                    (                    'host'                    )                    for                    (                    var                    i                    =                    0                    ;                    i                    <                    req.files.length;                    i++                    )                    {                    reqFiles.                    push                    (url                    +                    '/public/'                    +                    req.files[i]                    .filename)                    }                    const                    user                    =                    new                    User                    (                    {                    _id:                    new                    mongoose.Types.ObjectId                    (                    )                    ,                    avatar:                    reqFiles                    }                    )                    ;                    user.                    salvage                    (                    )                    .                    and so                    (                    issue                    =>                    {                    panel.                    log                    (result)                    ;                    res.                    condition                    (                    201                    )                    .                    json                    (                    {                    message:                    "Washed upload!"                    ,                    userCreated:                    {                    _id:                    result._id,                    avatar:                    result.avatar                    }                    }                    )                    }                    )                    .                    catch                    (                    err                    =>                    {                    console.                    log                    (err)                    ,                    res.                    status                    (                    500                    )                    .                    json                    (                    {                    fault:                    err                    }                    )                    ;                    }                    )                    }                    )                    router.                    get                    (                    "/"                    ,                    (                    req,                      res,                      next                    )                    =>                    {                    User.                    find                    (                    )                    .                    then                    (                    information                    =>                    {                    res.                    status                    (                    200                    )                    .                    json                    (                    {                    message:                    "User list retrieved successfully!"                    ,                    users:                    information                    }                    )                    ;                    }                    )                    ;                    }                    )                    ;                    module.exports                    =                    router;                                  

We used Multer's upload.array() method to upload the multiple files on the server. This method takes 2 arguments, beginning nosotros laissez passer the file name which we will exist using to store the file values. Second parameter relates to the number of file we can upload at a time. And so nosotros defined the reqFiles assortment here we will store the uploaded file's path with full URL.

Configure Node/Express Server

Create server.js file inside the backend folder. Then, identify the following lawmaking within the server.js file.

                                      const                    limited                    =                    require                    (                    'limited'                    )                    const                    mongoose                    =                    crave                    (                    'mongoose'                    )                    const                    cors                    =                    crave                    (                    'cors'                    )                    const                    bodyParser                    =                    require                    (                    'body-parser'                    )                    // Routes to Handle Request                    const                    userRoute                    =                    require                    (                    './routes/user.routes'                    )                    // MongoDB Setup                    mongoose                    .                    connect                    (                    'mongodb://127.0.0.1:27017/mydatabase'                    )                    .                    then                    (                    (                    x                    )                    =>                    {                    panel.                    log                    (                                          `                      Connected to Mongo! Database name: "                                              ${x.connections[                        0                        ]                        .proper noun}                                            "                      `                                        )                    }                    )                    .                    catch                    (                    (                    err                    )                    =>                    {                    console.                    error                    (                    'Fault connecting to mongo'                    ,                    err.reason)                    }                    )                    // Setup Limited.js                    const                    app                    =                    express                    (                    )                    app.                    utilize                    (bodyParser.                    json                    (                    )                    )                    app.                    utilise                    (                    bodyParser.                    urlencoded                    (                    {                    extended                    :                    false                    ,                    }                    )                    ,                    )                    app.                    use                    (                    cors                    (                    )                    )                    // Make Images "Uploads" Folder Publicly Available                    app.                    use                    (                    '/public'                    ,                    express.                    static                    (                    'public'                    )                    )                    // API Route                    app.                    use                    (                    '/api'                    ,                    userRoute)                    const                    port                    =                    process.env.                    PORT                    ||                    4000                    const                    server                    =                    app.                    listen                    (port,                    (                    )                    =>                    {                    panel.                    log                    (                    'Connected to port '                    +                    port)                    }                    )                    // Error                    app.                    use                    (                    (                    req,                      res,                      next                    )                    =>                    {                    // Error goes via `adjacent()` method                    setImmediate                    (                    (                    )                    =>                    {                    side by side                    (                    new                    Fault                    (                    'Something went incorrect'                    )                    )                    }                    )                    }                    )                    app.                    use                    (                    role                    (                    err,                      req,                      res,                      next                    )                    {                    console.                    error                    (err.bulletin)                    if                    (                    !err.statusCode)                    err.statusCode                    =                    500                    res.                    status                    (err.statusCode)                    .                    send                    (err.bulletin)                    }                    )                                  

Open the backend/parcel.json file and change primary from alphabetize.js to server.js.

                                      {                    ...   ...                    "main"                    :                    "server.js"                    ,                    ...   ...                    }                                  

Start Node Server

Open terminal and run command to starting time the MongoDB server.

                  mongod                

Then, open another terminal and run following command.

                  nodemon server.js                

Next, y'all can checkout node server running on the following Url: http://localhost:4000/api

API Method URL
GET http://localhost:4000/api
Postal service /api/create-user

You can test out Angular file uploading REST APIs Url in Postmen:

Angular Drag and Drop File UploadA

Create Athwart Elevate and Drop File Uploading Directive

In this footstep, nosotros volition create HostBinding and HostListeners to manage the drag and drop functionality for Angular file upload chore.

Run control to create directive in Angular projection.

                  ng chiliad d elevate-driblet-file-upload                

In the drag-drop-file-upload.directive.ts file, we will define 3 HostListners such every bit Dragover, Dragleave and Drop forth with HostBinding for background-color.

                                      import                    {                    Directive,                    EventEmitter,                    Output,                    HostListener,                    HostBinding,                    }                    from                    '@angular/core'                    ;                    @Directive                    (                    {                    selector                    :                    '[appDragDropFileUpload]'                    ,                    }                    )                    consign                    class                    DragDropFileUploadDirective                    {                    @Output                    (                    )                    fileDropped                    =                    new                    EventEmitter                    <whatever>                    (                    )                    ;                    @HostBinding                    (                    'fashion.background-colour'                    )                    private                    background                    =                    '#ffffff'                    ;                    // Dragover Outcome                    @HostListener                    (                    'dragover'                    ,                    [                    '$event'                    ]                    )                    dragOver                    (                                          outcome                      :                      whatsoever                    )                    {                    event.                    preventDefault                    (                    )                    ;                    outcome.                    stopPropagation                    (                    )                    ;                    this                    .background                    =                    '#e2eefd'                    ;                    }                    // Dragleave Event                    @HostListener                    (                    'dragleave'                    ,                    [                    '$event'                    ]                    )                    public                    dragLeave                    (                                          event                      :                      whatsoever                    )                    {                    event.                    preventDefault                    (                    )                    ;                    result.                    stopPropagation                    (                    )                    ;                    this                    .background                    =                    '#ffffff'                    ;                    }                    // Drop Event                    @HostListener                    (                    'drib'                    ,                    [                    '$effect'                    ]                    )                    public                    driblet                    (                                          event                      :                      whatsoever                    )                    {                    issue.                    preventDefault                    (                    )                    ;                    event.                    stopPropagation                    (                    )                    ;                    this                    .background                    =                    '#ffffff'                    ;                    const                    files                    =                    result.dataTransfer.files;                    if                    (files.length                    >                    0                    )                    {                    this                    .fileDropped.                    emit                    (files)                    ;                    }                    }                    }                                  

Create Angular Service

We demand to create Athwart service, hither in this file we will create a method in which we will brand HTTP POST request to store the uploaded files in the mongoDB database.

Use JavaScript's FormData() method to store the Reactive Forms value in the database via Reactive Form. To track the file upload progress ascertain the reportProgress and notice values in Http method.

First, create service file using given control in athwart project.

                  ng 1000 due south elevate-drib                

Next, open the src/app/drag-drop.service.ts file.

                                      import                    {                    Injectable                    }                    from                    '@athwart/core'                    ;                    import                    {                    Observable,                    throwError                    }                    from                    'rxjs'                    ; import                    {                    catchError                    }                    from                    'rxjs/operators'                    ; import                    {                    HttpErrorResponse,                    HttpClient                    }                    from                    '@angular/common/http'                    ;                                          @Injectable                      (                                        {                    providedIn                    :                    'root'                    }                    ) consign class DragdropService                    {                    constructor(individual http: HttpClient)                    {                    }                    addFiles(images: File)                    {                    var arr = []     var formData = new                    FormData                    (                    )                    ;                    arr.push button                    (images)                    ;     arr[0].forEach((item, i) =>                    {                    formData.append                    (                    'avatar'                    ,                    arr[0][i])                    ;                    }                    )     render this.http.mail service('http://localhost:4000/api/create-user', formData,                    {                    reportProgress                    :                    true,                    observe                    :                    'events'                    }                    ).pipe                    (                    catchError                    (this.errorMgmt)                    )                    }                    errorMgmt(error: HttpErrorResponse)                    {                    permit errorMessage =                    ''                    ;     if (error.error instanceof ErrorEvent)                    {                    // Get client-side error       errorMessage = error.mistake.message;                    }                    else                    {                    // Get server-side error       errorMessage = `Fault Code: $                    {mistake.condition}                    \nMessage: $                    {error.message}`;                    }                    console.log                    (errorMessage)                    ;                    return                    throwError                    (errorMessage)                    ;                    }                    }                                  

Create Drag and Drib File Upload Component

Now, we volition create the layout for drag and driblet file upload component. In this tutorial nosotros will exist using Reactive Forms to store the files and Node server to shop the files into the mongoDB database.

Import ReactiveFormsModule and HttpClientModule in app.module.ts file to enable the service.

                                      import                    {                    ReactiveFormsModule                    }                    from                    '@athwart/forms'                    ;                    import                    {HttpClientModule}                    from                    '@angular/common/http'                    ;                                          @                      NgModule                                        (                    {                    declarations:                    [                    ...                    ]                    ,                    imports:                    [                    ReactiveFormsModule,                    HttpClientModule                    ]                    ,                    bootstrap:                    [                    ...                    ]                    }                    )                    export                    form                    AppModule                    {                    }                                  

Next, add together the code inside the app/drag-drop.component.html file.

                                                                                    <div                      grade                                              =                        "container fileUploadWrapper"                                            >                                                                                      <form                      [formGroup]                                              =                        "form"                                            >                                                                                      <div                      form                                              =                        "row"                                            >                                        <!-- Progress Bar -->                                                                  <div                      course                                              =                        "col-dr.-12"                                            *ngIf                                              =                        "progress"                                            >                                                                                      <div                      grade                                              =                        "progress grade-grouping"                                            >                                                                                      <div                      course                                              =                        "progress-bar progress-bar-striped bg-success"                                            role                                              =                        "progressbar"                                            [style.width.%]                                              =                        "progress"                                            >                                                                                      </div                      >                                                                                      </div                      >                                                                                      </div                      >                                                                                      <div                      class                                              =                        "col-medico-12"                                            >                                                                                      <div                      course                                              =                        "fileupload"                                            appDragDropFileUpload                      (click)                                              =                        "fileField.click()"                                            (fileDropped)                                              =                        "upload($consequence)"                                            >                                                                                      <bridge                      grade                                              =                        "ddinfo"                                            >                    Choose a file or drag here                                              </span                      >                                                                                      <input                      type                                              =                        "file"                                            name                                              =                        "avatars"                                            #fileField                      (modify)                                              =                        "upload($whatsoever($upshot).target.files)"                                            hidden                      multiple                      />                                                                                      </div                      >                                                                                      </div                      >                                                                                      <div                      class                                              =                        "col-medico-12"                                            >                                                                                      <div                      class                                              =                        "epitome-list"                                            *ngFor                                              =                        "allow file of fileArr; let i = index"                                            >                                                                                      <div                      form                                              =                        "contour"                                            >                                                                                      <img                      [src]                                              =                        "sanitize(file['url'])"                                            alt                                              =                        "                        "                                            />                                                                                      </div                      >                                                                                      <p                      >                    {{ file.item.name }}                                              </p                      >                                                                                      </div                      >                                                                                      <p                      grade                                              =                        "bulletin"                                            >                    {{ msg }}                                              </p                      >                                                                                      </div                      >                                                                                      </div                      >                                                                                      </grade                      >                                                                                      </div                      >                                                      

Apply design to Angular drag and drib file uploading component, navigate to styles.css and paste the following code.

                                      *                    {                    box-sizing                    :                    edge-box;                    }                    body                    {                    margin                    :                    0;                    padding                    :                    25px 0 0 0;                    background                    :                    #291464;                    }                    .container                    {                    margin-pinnacle                    :                    30px;                    max-width                    :                    500px;                    }                    .progress                    {                    margin-bottom                    :                    30px;                    }                    .fileupload                    {                    background-prototype                    :                                          url                      ("./assets/upload-icon.png")                                        ;                    background-repeat                    :                    no-repeat;                    background-size                    :                    100px;                    background-position                    :                    center;                    groundwork-color                    :                    #ffffff;                    height                    :                    200px;                    width                    :                    100%;                    cursor                    :                    pointer;                    /* edge: 2px dashed #0f68ff; */                    border-radius                    :                    6px;                    margin-lesser                    :                    25px;                    groundwork-position                    :                    middle 28px;                    }                    .ddinfo                    {                    display                    :                    block;                    text-align                    :                    center;                    padding-summit                    :                    130px;                    color                    :                    #a0a1a2;                    }                    .prototype-listing                    {                    display                    :                    flex;                    width                    :                    100%;                    background                    :                    #C2DFFC;                    border                    :                    1px solid;                    border-radius                    :                    3px;                    padding                    :                    10px 10px 10px 15px;                    margin-bottom                    :                    10px;                    }                    .prototype-listing p                    {                    line-height                    :                    normal;                    padding                    :                    0;                    margin                    :                    0 0 0 14px;                    display                    :                    inline-block;                    position                    :                    relative;                    meridian                    :                    -2px;                    color                    :                    #150938;                    font-size                    :                    14px;                    }                    .message                    {                    text-align                    :                    middle;                    color                    :                    #C2DFFC;                    }                    .remove                    {                    background                    :                    transparent;                    border                    :                    none;                    cursor                    :                    pointer;                    }                    .profile                    {                    width                    :                    40px;                    height                    :                    40px;                    overflow                    :                    hidden;                    border-radius                    :                    4px;                    display                    :                    inline-block;                    }                    .profile img                    {                    width                    :                    100%;                    }                    .remove img                    {                    width                    :                    15px;                    position                    :                    relative;                    top                    :                    -2px;                    }                    .fileUploadWrapper .card-torso                    {                    max-meridian                    :                    330px;                    overflow                    :                    hidden;                    overflow-y                    :                    machine;                    }                                          @media                      (                      max-width                      :                      767px)                                        {                    .container                    {                    width                    :                    280px;                    margin                    :                    20px car 100px;                    }                    }                                  

in order to remove strict type check alert in typescript prepare "strict": imitation under compilerOptions in tsconfig.json file.

Paste the following code in app/drag-drop.component.ts file:

                                      import                    {                    Component,                    OnInit                    }                    from                    '@angular/cadre'                    ;                    import                    {                    FormBuilder,                    FormGroup,                    FormArray                    }                    from                    "@angular/forms"                    ;                    import                    {                    DragdropService                    }                    from                    "../dragdrop.service"                    ;                    import                    {                    HttpEvent,                    HttpEventType                    }                    from                    '@athwart/common/http'                    ;                    import                    {                    DomSanitizer                    }                    from                    '@angular/platform-browser'                    ;                    @Component                    (                    {                    selector:                    'app-drag-drop'                    ,                    templateUrl:                    './drag-drop.component.html'                    ,                    styleUrls:                    [                    './elevate-drop.component.css'                    ]                    }                    )                    consign                    grade                    DragDropComponent                    implements                    OnInit                    {                    fileArr                    =                    [                    ]                    ;                    imgArr                    =                    [                    ]                    ;                    fileObj                    =                    [                    ]                    ;                    form:                    FormGroup;                    msg:                    string                    ;                    progress:                    number                    =                    0                    ;                    constructor                    (                                          public                      fb:                      FormBuilder,                      private                      sanitizer:                      DomSanitizer,                      public                      dragdropService:                      DragdropService                    )                    {                    this                    .form                    =                    this                    .fb.                    group                    (                    {                    avatar:                    [                    null                    ]                    }                    )                    }                    ngOnInit                    (                    )                    {                    }                    upload                    (                    e                    )                    {                    const                    fileListAsArray                    =                    Array                    .                    from                    (e)                    ;                    fileListAsArray.                    forEach                    (                    (                    item,                      i                    )                    =>                    {                    const                    file                    =                    (due east                    as                    HTMLInputElement)                    ;                    const                    url                    =                    URL                    .                    createObjectURL                    (file[i]                    )                    ;                    this                    .imgArr.                    push button                    (url)                    ;                    this                    .fileArr.                    button                    (                    {                    item,                    url:                    url                    }                    )                    ;                    }                    )                    this                    .fileArr.                    forEach                    (                    (                    detail                    )                    =>                    {                    this                    .fileObj.                    push                    (item.item)                    }                    )                    // Set files form command                    this                    .form.                    patchValue                    (                    {                    avatar:                    this                    .fileObj                    }                    )                    this                    .class.                    get                    (                    'avatar'                    )                    .                    updateValueAndValidity                    (                    )                    // Upload to server                    this                    .dragdropService.                    addFiles                    (                    this                    .course.value.avatar)                    .                    subscribe                    (                    (                    outcome:                      HttpEvent<                      whatsoever                      >                                        )                    =>                    {                    switch                    (event.                    blazon                    )                    {                    instance                    HttpEventType.Sent:                    console                    .                    log                    (                    'Request has been made!'                    )                    ;                    break                    ;                    case                    HttpEventType.ResponseHeader:                    console                    .                    log                    (                    'Response header has been received!'                    )                    ;                    break                    ;                    case                    HttpEventType.UploadProgress:                    this                    .progress                    =                    Math.                    round                    (event.loaded                    /                    event.total                    *                    100                    )                    ;                    console                    .                    log                    (                                          `                      Uploaded!                                                                    ${                        this                        .progress}                                            %                      `                                        )                    ;                    break                    ;                    case                    HttpEventType.Response:                    console                    .                    log                    (                    'File uploaded successfully!'                    ,                    issue.body)                    ;                    setTimeout                    (                    (                    )                    =>                    {                    this                    .progress                    =                    0                    ;                    this                    .fileArr                    =                    [                    ]                    ;                    this                    .fileObj                    =                    [                    ]                    ;                    this                    .msg                    =                    "File uploaded successfully!"                    }                    ,                    3000                    )                    ;                    }                    }                    )                    }                    // Clean Url                    sanitize                    (                    url:                      string                                        )                    {                    return                    this                    .sanitizer.                    bypassSecurityTrustUrl                    (url)                    ;                    }                    }                                  

Next, get to app.component.html file and remove the electric current code and add the given component tag into it.

                                                                                    <app-drag-drop                      >                                                                                      </app-drag-driblet                      >                                                      

Run command to start your Athwart projection.

                  ng serve --open up                                  

Conclusion

Finally, Angular Elevate and Driblet multiple files uploading tutorial with MongoDB & Multer is completed. You can use the given link to download the sample project.

Git Repo