External DropZone

The External DropZone helps users to drag and drop files from their file systems to a dedicated user interface. The files are then sent to the specified server handlers, which are configured to receive them. The External DropZone can be implemented either by using the External DropZone Component, or by adding the External DropZone Directive to an element.

DropZone Component

The DropZone Component is a drag and drop tool. To link the external DropZone to the Upload, provide matching IDs to the zoneId options of the DropZone and the Upload.

import { FileInfo,  RemoveEvent, CancelEvent, FileRestrictions, SuccessEvent} from '@progress/kendo-angular-upload';
import { Component, ViewEncapsulation } from '@angular/core';

const photosUrl = 'https://www.telerik.com/kendo-angular-ui-develop/components/uploads/assets/';
const fillMyFiles = (count: number): Array<FileInfo> => {
  const files = [];
  for (let i = 0; i < count; i++) {
    files.push(
      {
        name: `${i}.png`,
        src: `${photosUrl}${i}.png`
      }
    );
  }
  return files;
};

@Component({
    selector: 'my-upload',
    styleUrls: ['styles.css'],
    encapsulation: ViewEncapsulation.None,
    template: `
      <div class="dropzone-wrapper">
        <div class="upload-wrapper">
          <kendo-uploaddropzone zoneId="myZone">
            Only JPEG and PNG files are allowed.
          </kendo-uploaddropzone>
          <kendo-upload
            zoneId="myZone"
            [saveUrl]="uploadSaveUrl"
            [removeUrl]="uploadRemoveUrl"
            (remove)="onRemove($event)"
            (cancel)="onCancel($event)"
            (success)="onUpload($event)"
            [restrictions]="myRestrictions"
            [showFileList]="false"
            >
          </kendo-upload>
        </div>
        <div class="images-wrapper">
          <div class="file-image" *ngFor="let image of myFiles">
              <img [src]="image.src" [alt]="image.name" />
          </div>
        </div>
      </div>
  `
})
export class UploadComponent {
  uploadSaveUrl = 'saveUrl'; // should represent an actual API endpoint
  uploadRemoveUrl = 'removeUrl'; // should represent an actual API endpoint

  public photosCount = 8;
  public myFiles = fillMyFiles(this.photosCount);

  public myRestrictions: FileRestrictions = {
    allowedExtensions: ['.jpg', '.png']
  };

  public onUpload(ev: SuccessEvent): void {
    if (this.myFiles && ev.files ) {
      ev.files.forEach((file: FileInfo) => {
        if (file.rawFile && !file.validationErrors && ev.operation === 'upload') {
          const reader  = new FileReader();

          reader.onloadend = () => {
            this.myFiles.push({...file, src: <string>reader.result});
          };
          reader.readAsDataURL(file.rawFile);
        }
      });
    }
  }

  public onCancel(ev: CancelEvent): void {
    ev.files.forEach((file: FileInfo) => {
      this.myFiles = this.myFiles.filter(f => f.uid !== file.uid);
    });
  }

  public onRemove(ev: RemoveEvent): void {
    ev.files.forEach((file: FileInfo) => {
      this.myFiles = this.myFiles.filter(f => f.uid !== file.uid);
    });
  }
}

.dropzone-wrapper {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  min-height: 420px;
}

.upload-wrapper, .fileselect-wrapper {
  display: flex;
  flex-direction: column;
  max-width: 375.2px;
}

kendo-uploaddropzone {
  margin: 0 8px;
  flex-grow: 1;
}

kendo-upload, kendo-fileselect {
  margin: 8px 8px 0 8px;
}

.images-wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  justify-items: center;
  align-content: start;
  column-gap:10px;
  row-gap: 10px;
  border: 1px solid;
  border-color: #EBEBEB;
  padding:10px;
}

.file-image {
  width: 110px;
  height: 110px;
  align-self: flex-start;
}

img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.wrapper {
  display:flex;
  flex-direction: column;
}
.custom-dropzone {
  border: 1px solid;
  border-color: #EBEBEB;
  margin: 8px;
  height: 200px;
}

.custom-dropzone p {
  margin: 10px;
}
import { Component, Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpProgressEvent, HttpEventType, HttpResponse } from '@angular/common/http';
import { Observable, of, concat } from 'rxjs';
import { delay } from 'rxjs/operators';

@Component({
    selector: 'my-app',
    template: `<my-upload></my-upload>`
})
export class AppComponent {
}

/*
  Mocked backend service.
  For further details, check
  https://angular.io/guide/http#writing-an-interceptor
*/

@Injectable()
export class UploadInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (req.url === 'saveUrl') {
      const events: Observable<HttpEvent<any>>[] = [0, 30, 60, 100].map((x) => of(<HttpProgressEvent>{
        type: HttpEventType.UploadProgress,
        loaded: x,
        total: 100
      }).pipe(delay(1000)));

      const success = of(new HttpResponse({ status: 200 })).pipe(delay(1000));
      events.push(success);

      return concat(...events);
    }

    if (req.url === 'removeUrl') {
        return of(new HttpResponse({ status: 200 }));
    }

    return next.handle(req);
  }
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { UploadModule } from '@progress/kendo-angular-upload';
import { UploadComponent } from './upload.component';
import { UploadInterceptor } from './app.component';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';


import { AppComponent } from './app.component';

@NgModule({
    imports:      [ BrowserModule, HttpClientModule, UploadModule, BrowserAnimationsModule, FormsModule, ReactiveFormsModule ],
    declarations: [ AppComponent, UploadComponent ],
    bootstrap:    [ AppComponent ],
    providers: [
      {
        provide: HTTP_INTERCEPTORS,
        useClass: UploadInterceptor,
        multi: true
      }
    ]
  })

  export class AppModule { }
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

enableProdMode();

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

DropZone Directive

The DropZone Directive allows you to create custom elements with a drag and drop upload functionality. To link the custom element to the Upload, provide matching IDs to the kendoUploadDropZone and the Upload zoneId option.

import { Component } from '@angular/core';

@Component({
    selector: 'my-upload',
    styleUrls: ['styles.css'],
    template: `
      <div class="wrapper">
          <div class="custom-dropzone" [kendoUploadDropZone]="'myZone'">
            <p>Drop files here...</p>
          </div>
          <kendo-upload
            zoneId="myZone"
            [saveUrl]="uploadSaveUrl"
            [removeUrl]="uploadRemoveUrl"
            >
          </kendo-upload>
      </div>
  `
})
export class UploadComponent {
  uploadSaveUrl = 'saveUrl'; // should represent an actual API endpoint
  uploadRemoveUrl = 'removeUrl'; // should represent an actual API endpoint
}
.dropzone-wrapper {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  min-height: 420px;
}

.upload-wrapper, .fileselect-wrapper {
  display: flex;
  flex-direction: column;
  max-width: 375.2px;
}

kendo-uploaddropzone {
  margin: 0 8px;
  flex-grow: 1;
}

kendo-upload, kendo-fileselect {
  margin: 8px 8px 0 8px;
}

.images-wrapper {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  justify-items: center;
  align-content: start;
  column-gap:10px;
  row-gap: 10px;
  border: 1px solid;
  border-color: #EBEBEB;
  padding:10px;
}

.file-image {
  width: 110px;
  height: 110px;
  align-self: flex-start;
}

img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.wrapper {
  display:flex;
  flex-direction: column;
}
.custom-dropzone {
  border: 1px solid;
  border-color: #EBEBEB;
  margin: 8px;
  height: 200px;
}

.custom-dropzone p {
  margin: 10px;
}
import { Component, Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpProgressEvent, HttpEventType, HttpResponse } from '@angular/common/http';
import { Observable, of, concat } from 'rxjs';
import { delay } from 'rxjs/operators';

@Component({
    selector: 'my-app',
    template: `<my-upload></my-upload>`
})
export class AppComponent {
}

/*
  Mocked backend service.
  For further details, check
  https://angular.io/guide/http#writing-an-interceptor
*/

@Injectable()
export class UploadInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    if (req.url === 'saveUrl') {
      const events: Observable<HttpEvent<any>>[] = [0, 30, 60, 100].map((x) => of(<HttpProgressEvent>{
        type: HttpEventType.UploadProgress,
        loaded: x,
        total: 100
      }).pipe(delay(1000)));

      const success = of(new HttpResponse({ status: 200 })).pipe(delay(1000));
      events.push(success);

      return concat(...events);
    }

    if (req.url === 'removeUrl') {
        return of(new HttpResponse({ status: 200 }));
    }

    return next.handle(req);
  }
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { UploadModule } from '@progress/kendo-angular-upload';
import { UploadComponent } from './upload.component';
import { UploadInterceptor } from './app.component';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';


import { AppComponent } from './app.component';

@NgModule({
    imports:      [ BrowserModule, HttpClientModule, UploadModule, BrowserAnimationsModule, FormsModule, ReactiveFormsModule ],
    declarations: [ AppComponent, UploadComponent ],
    bootstrap:    [ AppComponent ],
    providers: [
      {
        provide: HTTP_INTERCEPTORS,
        useClass: UploadInterceptor,
        multi: true
      }
    ]
  })

  export class AppModule { }
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

enableProdMode();

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

In this article