From 74306fc210228f49c49de1401b5ea196791847d1 Mon Sep 17 00:00:00 2001 From: Gilles Gauthier Date: Wed, 12 Jul 2017 11:35:55 +0200 Subject: [PATCH 01/11] Update simple demo Fix correct path for isHTML5 option --- demo/src/app/components/file-upload/simple-demo.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/src/app/components/file-upload/simple-demo.html b/demo/src/app/components/file-upload/simple-demo.html index d0e4c81..a358c53 100644 --- a/demo/src/app/components/file-upload/simple-demo.html +++ b/demo/src/app/components/file-upload/simple-demo.html @@ -61,8 +61,8 @@ {{ item?.file?.name }} - {{ item?.file?.size/1024/1024 | number:'.2' }} MB - + {{ item?.file?.size/1024/1024 | number:'.2' }} MB +
From 28d98bc8af1735eb6cc29af75a945ec5c871ff53 Mon Sep 17 00:00:00 2001 From: Joshua Terrill Date: Tue, 1 Aug 2017 15:08:21 -0700 Subject: [PATCH 02/11] Added onFileDrop() event to documentation In case anyone wants to use the onFileDrop event to handle the files in their own way, I've added it to the documentation. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 351d2c8..9e94668 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ Easy to use Angular2 directives for files upload ([demo](http://valor-software.g - `fileOver` - it fires during 'over' and 'out' events for Drop Area; returns `boolean`: `true` if file is over Drop Area, `false` in case of out. See using in [ts demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.ts) and [html demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.html) + - `onFileDrop` - it fires after a file has been dropped on a Drop Area; you can pass in `$event` to get the list of files that were dropped. i.e. `(onFileDrop)="dropped($event)"` # Troubleshooting From eca11298ee0b16ff731566f8ef68aa58878d98d1 Mon Sep 17 00:00:00 2001 From: Adrian Date: Tue, 26 Sep 2017 21:40:55 +0300 Subject: [PATCH 03/11] Fixed karma config --- karma.conf.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index 1a74f89..2d7216a 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -6,18 +6,18 @@ const customLaunchers = require('./scripts/sauce-browsers').customLaunchers; module.exports = function (config) { const configuration = { basePath: '', - frameworks: ['jasmine', 'angular-cli'], + frameworks: ['jasmine', '@angular/cli'], plugins: [ require('karma-jasmine'), require('karma-chrome-launcher'), require('karma-remap-istanbul'), - require('angular-cli/plugins/karma') + require('@angular/cli/plugins/karma') ], files: [ {pattern: './scripts/test.ts', watched: false} ], preprocessors: { - './scripts/test.ts': ['angular-cli'] + './scripts/test.ts': ['@angular/cli'] }, remapIstanbulReporter: { reports: { From 6bdf60fac4db801ff4ccd3089a801833551990ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20F=C3=A2ciu?= Date: Tue, 26 Sep 2017 23:04:21 +0300 Subject: [PATCH 04/11] Adding tests for file drop directive --- src/file-upload/file-drop.directive.ts | 47 ++++----- src/spec/file-drop.directive.spec.ts | 137 +++++++++++++++++++++++-- 2 files changed, 147 insertions(+), 37 deletions(-) diff --git a/src/file-upload/file-drop.directive.ts b/src/file-upload/file-drop.directive.ts index 6c1c4ff..b04ae51 100644 --- a/src/file-upload/file-drop.directive.ts +++ b/src/file-upload/file-drop.directive.ts @@ -1,29 +1,29 @@ import { Directive, EventEmitter, ElementRef, HostListener, Input, Output } from '@angular/core'; -import { FileUploader } from './file-uploader.class'; +import { FileUploader, FileUploaderOptions } from './file-uploader.class'; -@Directive({selector: '[ng2FileDrop]'}) +@Directive({ selector: '[ng2FileDrop]' }) export class FileDropDirective { - @Input() public uploader:FileUploader; - @Output() public fileOver:EventEmitter = new EventEmitter(); - @Output() public onFileDrop:EventEmitter = new EventEmitter(); + @Input() public uploader: FileUploader; + @Output() public fileOver: EventEmitter = new EventEmitter(); + @Output() public onFileDrop: EventEmitter = new EventEmitter(); - protected element:ElementRef; + protected element: ElementRef; - public constructor(element:ElementRef) { + public constructor(element: ElementRef) { this.element = element; } - public getOptions():any { + public getOptions(): FileUploaderOptions { return this.uploader.options; } - public getFilters():any { + public getFilters(): any { return {}; } - @HostListener('drop', ['$event']) - public onDrop(event:any):void { + @HostListener('drop', [ '$event' ]) + public onDrop(event: any): void { let transfer = this._getTransfer(event); if (!transfer) { return; @@ -37,8 +37,8 @@ export class FileDropDirective { this.onFileDrop.emit(transfer.files); } - @HostListener('dragover', ['$event']) - public onDragOver(event:any):void { + @HostListener('dragover', [ '$event' ]) + public onDragOver(event: any): void { let transfer = this._getTransfer(event); if (!this._haveFiles(transfer.types)) { return; @@ -49,10 +49,10 @@ export class FileDropDirective { this.fileOver.emit(true); } - @HostListener('dragleave', ['$event']) - public onDragLeave(event:any):any { + @HostListener('dragleave', [ '$event' ]) + public onDragLeave(event: any): any { if ((this as any).element) { - if (event.currentTarget === (this as any).element[0]) { + if (event.currentTarget === (this as any).element[ 0 ]) { return; } } @@ -61,16 +61,16 @@ export class FileDropDirective { this.fileOver.emit(false); } - protected _getTransfer(event:any):any { + protected _getTransfer(event: any): any { return event.dataTransfer ? event.dataTransfer : event.originalEvent.dataTransfer; // jQuery fix; } - protected _preventAndStop(event:any):any { + protected _preventAndStop(event: any): any { event.preventDefault(); event.stopPropagation(); } - protected _haveFiles(types:any):any { + protected _haveFiles(types: any): any { if (!types) { return false; } @@ -83,13 +83,4 @@ export class FileDropDirective { return false; } } - - /* - _addOverClass(item:any):any { - item.addOverClass(); - } - - _removeOverClass(item:any):any { - item.removeOverClass(); - }*/ } diff --git a/src/spec/file-drop.directive.spec.ts b/src/spec/file-drop.directive.spec.ts index 6b5a268..5734bd8 100644 --- a/src/spec/file-drop.directive.spec.ts +++ b/src/spec/file-drop.directive.spec.ts @@ -1,28 +1,147 @@ -import { Component } from '@angular/core'; +import { Component, DebugElement } from '@angular/core'; +import { By } from '@angular/platform-browser'; import { inject, ComponentFixture, TestBed } from '@angular/core/testing'; import { FileUploader } from '../file-upload/file-uploader.class'; import { FileUploadModule } from '../file-upload/file-upload.module'; +import { FileDropDirective } from '../file-upload/file-drop.directive'; @Component({ selector: 'container', - template: `` + template: `` }) export class ContainerComponent { - public uploader:FileUploader = new FileUploader({url: 'localhost:3000'}); + public get url(): string { return 'localhost:3000'; } + public uploader: FileUploader = new FileUploader({ url: this.url }); } describe('Directive: FileSelectDirective', () => { + let fixture: ComponentFixture; + let hostComponent: ContainerComponent; + let directiveElement: DebugElement; + let fileDropDirective: FileDropDirective; + beforeEach(() => { TestBed.configureTestingModule({ - imports: [FileUploadModule], - declarations: [ContainerComponent], - providers: [ContainerComponent] + imports: [ FileUploadModule ], + declarations: [ ContainerComponent ], + providers: [ ContainerComponent ] }); }); - it('should be fine', inject([ContainerComponent], (fixture:ComponentFixture) => { - expect(fixture).not.toBeNull(); - })); + beforeEach(() => { + fixture = TestBed.createComponent(ContainerComponent); + hostComponent = fixture.componentInstance; + + fixture.detectChanges(); + + directiveElement = fixture.debugElement.query(By.directive(FileDropDirective)); + fileDropDirective = directiveElement.injector.get(FileDropDirective) as FileDropDirective; + }); + + it('can be initialized', () => { + expect(fixture).toBeDefined(); + expect(hostComponent).toBeDefined(); + expect(fileDropDirective).toBeDefined(); + }); + + it('can set file uploader', () => { + expect(fileDropDirective.uploader).toBe(hostComponent.uploader); + }); + + it('can get uploader options', () => { + const options = fileDropDirective.getOptions(); + + // Check url set through binding + expect(options.url).toBe(hostComponent.url); + + // Check default options + expect(options.autoUpload).toBeFalsy(); + expect(options.isHTML5).toBeTruthy(); + expect(options.removeAfterUpload).toBeFalsy(); + expect(options.disableMultipart).toBeFalsy(); + }); + + it('can get filters', () => { + const filters = fileDropDirective.getFilters(); + + // TODO: Update test once implemented + expect(filters).toEqual({}); + }); + + it('handles drop event', () => { + spyOn(fileDropDirective, 'onDrop'); + + directiveElement.triggerEventHandler('drop', getFakeEvent()); + + expect(fileDropDirective.onDrop).toHaveBeenCalled(); + }); + + it('adds file to upload', () => { + spyOn(fileDropDirective.uploader, 'addToQueue'); + + let fileOverData; + fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data); + + let fileDropData; + fileDropDirective.onFileDrop.subscribe((data: File[]) => fileDropData = data); + + fileDropDirective.onDrop(getFakeEvent()); + + const uploadedFiles = getFakeEvent().dataTransfer.files; + const expectedArguments = [ uploadedFiles, fileDropDirective.getOptions(), fileDropDirective.getFilters() ]; + + expect(fileDropDirective.uploader.addToQueue).toHaveBeenCalledWith(...expectedArguments); + expect(fileOverData).toBeFalsy(); + expect(fileDropData).toEqual(uploadedFiles); + }); + + it('handles dragover event', () => { + spyOn(fileDropDirective, 'onDragOver'); + + directiveElement.triggerEventHandler('dragover', getFakeEvent()); + + expect(fileDropDirective.onDragOver).toHaveBeenCalled(); + }); + + it('handles file over', () => { + let fileOverData; + fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data); + + fileDropDirective.onDragOver(getFakeEvent()); + + expect(fileOverData).toBeTruthy(); + }); + + it('handles dragleave event', () => { + spyOn(fileDropDirective, 'onDragLeave'); + + directiveElement.triggerEventHandler('dragleave', getFakeEvent()); + + expect(fileDropDirective.onDragLeave).toHaveBeenCalled(); + }); + + it('handles file over leave', () => { + let fileOverData; + fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data); + + fileDropDirective.onDragLeave(getFakeEvent()); + + expect(fileOverData).toBeFalsy(); + }); }); + +function getFakeEvent(): any { + return { + dataTransfer: { + files: [ 'foo.bar' ], + types: [ 'Files' ] + }, + preventDefault: () => undefined, + stopPropagation: () => undefined + } +} From 0df30f996fd9c1f3e46bf70829e98187b55ae061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20F=C3=A2ciu?= Date: Sun, 1 Oct 2017 17:07:54 +0300 Subject: [PATCH 05/11] Fixing test execution on CI --- karma.conf.js | 12 +++++------- package.json | 5 +++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/karma.conf.js b/karma.conf.js index 2d7216a..152285d 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -10,7 +10,7 @@ module.exports = function (config) { plugins: [ require('karma-jasmine'), require('karma-chrome-launcher'), - require('karma-remap-istanbul'), + require('karma-coverage-istanbul-reporter'), require('@angular/cli/plugins/karma') ], files: [ @@ -19,18 +19,16 @@ module.exports = function (config) { preprocessors: { './scripts/test.ts': ['@angular/cli'] }, - remapIstanbulReporter: { - reports: { - html: 'coverage', - lcovonly: './coverage/coverage.lcov' - } + coverageIstanbulReporter: { + reports: [ 'html', 'lcovonly' ], + fixWebpackSourcePaths: false }, angularCli: { config: './angular-cli.json', environment: 'dev' }, reporters: config.angularCli && config.angularCli.codeCoverage - ? ['dots', 'karma-remap-istanbul'] + ? ['dots', 'coverage-istanbul'] : ['dots'], port: 9876, colors: true, diff --git a/package.json b/package.json index 30f6f7e..f8dbcb1 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "@angular/core": "^2.3.1 || >=4.0.0" }, "devDependencies": { + "@angular/cli": "1.0.0", "@angular/common": "2.4.3", "@angular/compiler": "2.4.3", "@angular/compiler-cli": "2.4.3", @@ -64,7 +65,6 @@ "@types/marked": "0.0.28", "@types/node": "7.0.0", "@types/webpack": "^2.2.1", - "@angular/cli": "1.0.0", "bootstrap": "3.3.7", "chokidar-cli": "1.2.0", "classlist-polyfill": "1.0.3", @@ -87,6 +87,7 @@ "karma": "1.4.0", "karma-chrome-launcher": "^2.0.0", "karma-cli": "^1.0.1", + "karma-coverage-istanbul-reporter": "^1.3.0", "karma-jasmine": "^1.0.2", "karma-remap-istanbul": "0.4.0", "karma-sauce-launcher": "1.1.0", @@ -94,9 +95,9 @@ "lodash": "4.17.4", "markdown-loader": "^0.1.7", "marked": "0.3.6", - "ngx-bootstrap": "1.6.6", "ng2-page-scroll": "4.0.0-beta.2", "ngm-cli": "0.4.0", + "ngx-bootstrap": "1.6.6", "npm-run-all": "^4.0.1", "pre-commit": "1.2.2", "protractor": "5.0.0", From 048f534aa23c54bd66a9c739485e1e56e93679f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20F=C3=A2ciu?= Date: Sun, 1 Oct 2017 17:33:38 +0300 Subject: [PATCH 06/11] Adding tests for file select directive --- src/file-upload/file-select.directive.ts | 18 ++--- src/spec/file-drop.directive.spec.ts | 22 +++--- src/spec/file-select.directive.spec.ts | 99 ++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 20 deletions(-) create mode 100644 src/spec/file-select.directive.spec.ts diff --git a/src/file-upload/file-select.directive.ts b/src/file-upload/file-select.directive.ts index ed84cba..8060647 100644 --- a/src/file-upload/file-select.directive.ts +++ b/src/file-upload/file-select.directive.ts @@ -4,30 +4,30 @@ import { FileUploader } from './file-uploader.class'; // todo: filters -@Directive({selector: '[ng2FileSelect]'}) +@Directive({ selector: '[ng2FileSelect]' }) export class FileSelectDirective { - @Input() public uploader:FileUploader; + @Input() public uploader: FileUploader; - protected element:ElementRef; + protected element: ElementRef; - public constructor(element:ElementRef) { + public constructor(element: ElementRef) { this.element = element; } - public getOptions():any { + public getOptions(): any { return this.uploader.options; } - public getFilters():any { - return void 0; + public getFilters(): any { + return {}; } - public isEmptyAfterSelection():boolean { + public isEmptyAfterSelection(): boolean { return !!this.element.nativeElement.attributes.multiple; } @HostListener('change') - public onChange():any { + public onChange(): any { // let files = this.uploader.isHTML5 ? this.element.nativeElement[0].files : this.element.nativeElement[0]; let files = this.element.nativeElement.files; let options = this.getOptions(); diff --git a/src/spec/file-drop.directive.spec.ts b/src/spec/file-drop.directive.spec.ts index 5734bd8..58bca0e 100644 --- a/src/spec/file-drop.directive.spec.ts +++ b/src/spec/file-drop.directive.spec.ts @@ -8,17 +8,17 @@ import { FileDropDirective } from '../file-upload/file-drop.directive'; @Component({ selector: 'container', - template: `` + >` }) export class ContainerComponent { public get url(): string { return 'localhost:3000'; } public uploader: FileUploader = new FileUploader({ url: this.url }); } -describe('Directive: FileSelectDirective', () => { +describe('Directive: FileDropDirective', () => { let fixture: ComponentFixture; let hostComponent: ContainerComponent; @@ -76,7 +76,7 @@ describe('Directive: FileSelectDirective', () => { it('handles drop event', () => { spyOn(fileDropDirective, 'onDrop'); - directiveElement.triggerEventHandler('drop', getFakeEvent()); + directiveElement.triggerEventHandler('drop', getFakeEventData()); expect(fileDropDirective.onDrop).toHaveBeenCalled(); }); @@ -90,9 +90,9 @@ describe('Directive: FileSelectDirective', () => { let fileDropData; fileDropDirective.onFileDrop.subscribe((data: File[]) => fileDropData = data); - fileDropDirective.onDrop(getFakeEvent()); + fileDropDirective.onDrop(getFakeEventData()); - const uploadedFiles = getFakeEvent().dataTransfer.files; + const uploadedFiles = getFakeEventData().dataTransfer.files; const expectedArguments = [ uploadedFiles, fileDropDirective.getOptions(), fileDropDirective.getFilters() ]; expect(fileDropDirective.uploader.addToQueue).toHaveBeenCalledWith(...expectedArguments); @@ -103,7 +103,7 @@ describe('Directive: FileSelectDirective', () => { it('handles dragover event', () => { spyOn(fileDropDirective, 'onDragOver'); - directiveElement.triggerEventHandler('dragover', getFakeEvent()); + directiveElement.triggerEventHandler('dragover', getFakeEventData()); expect(fileDropDirective.onDragOver).toHaveBeenCalled(); }); @@ -112,7 +112,7 @@ describe('Directive: FileSelectDirective', () => { let fileOverData; fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data); - fileDropDirective.onDragOver(getFakeEvent()); + fileDropDirective.onDragOver(getFakeEventData()); expect(fileOverData).toBeTruthy(); }); @@ -120,7 +120,7 @@ describe('Directive: FileSelectDirective', () => { it('handles dragleave event', () => { spyOn(fileDropDirective, 'onDragLeave'); - directiveElement.triggerEventHandler('dragleave', getFakeEvent()); + directiveElement.triggerEventHandler('dragleave', getFakeEventData()); expect(fileDropDirective.onDragLeave).toHaveBeenCalled(); }); @@ -129,13 +129,13 @@ describe('Directive: FileSelectDirective', () => { let fileOverData; fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data); - fileDropDirective.onDragLeave(getFakeEvent()); + fileDropDirective.onDragLeave(getFakeEventData()); expect(fileOverData).toBeFalsy(); }); }); -function getFakeEvent(): any { +function getFakeEventData(): any { return { dataTransfer: { files: [ 'foo.bar' ], diff --git a/src/spec/file-select.directive.spec.ts b/src/spec/file-select.directive.spec.ts new file mode 100644 index 0000000..dfddc52 --- /dev/null +++ b/src/spec/file-select.directive.spec.ts @@ -0,0 +1,99 @@ +import { TestBed, ComponentFixture } from '@angular/core/testing'; +import { Component, DebugElement } from '@angular/core'; +import { By } from '@angular/platform-browser'; + +import { FileUploadModule } from '../file-upload/file-upload.module'; +import { FileSelectDirective } from '../file-upload/file-select.directive'; +import { FileUploader } from '../file-upload/file-uploader.class'; + +@Component({ + selector: 'container', + template: `` +}) +export class ContainerComponent { + public get url(): string { return 'localhost:3000'; } + public uploader: FileUploader = new FileUploader({ url: this.url }); +} + +describe('Directive: FileSelectDirective', () => { + let fixture: ComponentFixture; + let hostComponent: ContainerComponent; + let directiveElement: DebugElement; + let fileSelectDirective: FileSelectDirective; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ FileUploadModule ], + declarations: [ ContainerComponent ], + providers: [ ContainerComponent ] + }); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ContainerComponent); + hostComponent = fixture.componentInstance; + + fixture.detectChanges(); + + directiveElement = fixture.debugElement.query(By.directive(FileSelectDirective)); + fileSelectDirective = directiveElement.injector.get(FileSelectDirective) as FileSelectDirective; + }); + + it('can be initialized', () => { + expect(fixture).toBeDefined(); + expect(hostComponent).toBeDefined(); + expect(fileSelectDirective).toBeDefined(); + }); + + it('can set file uploader', () => { + expect(fileSelectDirective.uploader).toBe(hostComponent.uploader); + }); + + it('can get uploader options', () => { + const options = fileSelectDirective.getOptions(); + + // Check url set through binding + expect(options.url).toBe(hostComponent.url); + + // Check default options + expect(options.autoUpload).toBeFalsy(); + expect(options.isHTML5).toBeTruthy(); + expect(options.removeAfterUpload).toBeFalsy(); + expect(options.disableMultipart).toBeFalsy(); + }); + + it('can get filters', () => { + const filters = fileSelectDirective.getFilters(); + + // TODO: Update test once implemented + expect(filters).toEqual({}); + }); + + it('can check if element is empty', () => { + const isElementEmpty = fileSelectDirective.isEmptyAfterSelection(); + + expect(isElementEmpty).toBeFalsy(); + }); + + it('can listed on change event', () => { + spyOn(fileSelectDirective, 'onChange'); + + directiveElement.triggerEventHandler('change', {}); + + expect(fileSelectDirective.onChange).toHaveBeenCalled(); + }); + + it('handles change event', () => { + spyOn(fileSelectDirective.uploader, 'addToQueue'); + + fileSelectDirective.onChange(); + + const expectedArguments = [ directiveElement.nativeElement.files, + fileSelectDirective.getOptions(), + fileSelectDirective.getFilters() ]; + expect(fileSelectDirective.uploader.addToQueue).toHaveBeenCalledWith(...expectedArguments); + }); +}); From 5357a243f6d1ec9bbb70e973460ff773b2c4f361 Mon Sep 17 00:00:00 2001 From: David Martins Date: Wed, 4 Oct 2017 16:36:48 -0300 Subject: [PATCH 07/11] Added event with return of request --- src/file-upload/file-uploader.class.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/file-upload/file-uploader.class.ts b/src/file-upload/file-uploader.class.ts index 5f17770..998352c 100644 --- a/src/file-upload/file-uploader.class.ts +++ b/src/file-upload/file-uploader.class.ts @@ -1,3 +1,4 @@ +import { EventEmitter } from '@angular/core'; import { FileLikeObject } from './file-like-object.class'; import { FileItem } from './file-item.class'; import { FileType } from './file-type.class'; @@ -43,6 +44,7 @@ export class FileUploader { public _nextIndex:number = 0; public autoUpload:any; public authTokenHeader: string; + public response: EventEmitter; public options:FileUploaderOptions = { autoUpload: false, @@ -56,6 +58,7 @@ export class FileUploader { public constructor(options:FileUploaderOptions) { this.setOptions(options); + this.response = new EventEmitter(); } public setOptions(options:FileUploaderOptions):void { @@ -358,6 +361,11 @@ export class FileUploader { xhr.setRequestHeader(this.authTokenHeader, this.authToken); } xhr.send(sendable); + xhr.onreadystatechange = function() { + if (xhr.readyState == XMLHttpRequest.DONE) { + this.response.emit(xhr.responseText) + } + } this._render(); } From 14812e0cf729c367e733408afbb22b540893eb14 Mon Sep 17 00:00:00 2001 From: David Martins Date: Wed, 4 Oct 2017 16:52:28 -0300 Subject: [PATCH 08/11] Added option to send request body modifier function --- src/file-upload/file-uploader.class.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/file-upload/file-uploader.class.ts b/src/file-upload/file-uploader.class.ts index 998352c..1e96861 100644 --- a/src/file-upload/file-uploader.class.ts +++ b/src/file-upload/file-uploader.class.ts @@ -33,6 +33,8 @@ export interface FileUploaderOptions { itemAlias?: string; authTokenHeader?: string; additionalParameter?:{[key: string]: any}; + formatDataFunction?:Function; + formatDataFunctionIsAsync?:boolean; } export class FileUploader { @@ -51,7 +53,9 @@ export class FileUploader { isHTML5: true, filters: [], removeAfterUpload: false, - disableMultipart: false + disableMultipart: false, + formatDataFunction: function (item:FileItem) { return item._file; }, + formatDataFunctionIsAsync: false }; protected _failFilterIndex:number; @@ -318,7 +322,7 @@ export class FileUploader { }); } } else { - sendable = item._file; + sendable = this.options.formatDataFunction(item); } xhr.upload.onprogress = (event:any) => { @@ -360,12 +364,18 @@ export class FileUploader { if (this.authToken) { xhr.setRequestHeader(this.authTokenHeader, this.authToken); } - xhr.send(sendable); xhr.onreadystatechange = function() { if (xhr.readyState == XMLHttpRequest.DONE) { this.response.emit(xhr.responseText) } } + if (this.options.formatDataFunctionIsAsync) { + sendable.then( + (result:any) => xhr.send(JSON.stringify(result)) + ); + } else { + xhr.send(sendable); + } this._render(); } From c84046e86ec95e2392da4d287e21582d781ebfa4 Mon Sep 17 00:00:00 2001 From: David Martins Date: Wed, 4 Oct 2017 17:03:16 -0300 Subject: [PATCH 09/11] Update README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9e94668..8c099d5 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,8 @@ Easy to use Angular2 directives for files upload ([demo](http://valor-software.g 2. `authToken` - Auth token that will be applied as 'Authorization' header during file send. 3. `disableMultipart` - If 'true', disable using a multipart form for file upload and instead stream the file. Some APIs (e.g. Amazon S3) may expect the file to be streamed rather than sent via a form. Defaults to false. 4. `itemAlias` - item alias (form name redefenition) + 5. `formatDataFunction` - Function to modify the request body. 'DisableMultipart' must be 'true' for this function to be called. + 6. `formatDataFunctionIsAsync` - Informs if the function sent in 'formatDataFunction' is asynchronous. Defaults to false. ### Events From 4c0c4c70bcbfe6acf4158ffbf10bb53a275bd184 Mon Sep 17 00:00:00 2001 From: David Martins Date: Fri, 6 Oct 2017 17:20:26 -0300 Subject: [PATCH 10/11] Fixing bug in response --- src/file-upload/file-uploader.class.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/file-upload/file-uploader.class.ts b/src/file-upload/file-uploader.class.ts index 1e96861..056eb18 100644 --- a/src/file-upload/file-uploader.class.ts +++ b/src/file-upload/file-uploader.class.ts @@ -298,6 +298,7 @@ export class FileUploader { } protected _xhrTransport(item:FileItem):any { + let that = this; let xhr = item._xhr = new XMLHttpRequest(); let sendable:any; this._onBeforeUploadItem(item); @@ -366,7 +367,7 @@ export class FileUploader { } xhr.onreadystatechange = function() { if (xhr.readyState == XMLHttpRequest.DONE) { - this.response.emit(xhr.responseText) + that.response.emit(xhr.responseText) } } if (this.options.formatDataFunctionIsAsync) { From be7f164d98ce966ceccddd3e403b5cb2812eac2e Mon Sep 17 00:00:00 2001 From: David Martins Date: Fri, 6 Oct 2017 17:22:20 -0300 Subject: [PATCH 11/11] Updating example --- .../components/file-upload/simple-demo.html | 12 +++++++ .../app/components/file-upload/simple-demo.ts | 33 +++++++++++++++++-- demo/src/doc.md | 4 +++ demo/src/tsconfig.json | 2 +- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/demo/src/app/components/file-upload/simple-demo.html b/demo/src/app/components/file-upload/simple-demo.html index a358c53..4333d7b 100644 --- a/demo/src/app/components/file-upload/simple-demo.html +++ b/demo/src/app/components/file-upload/simple-demo.html @@ -115,4 +115,16 @@ +

+ +
+
+
+
Response
+
+ {{ response }} +
+
+
+
diff --git a/demo/src/app/components/file-upload/simple-demo.ts b/demo/src/app/components/file-upload/simple-demo.ts index 1d2f354..4a26a21 100644 --- a/demo/src/app/components/file-upload/simple-demo.ts +++ b/demo/src/app/components/file-upload/simple-demo.ts @@ -9,9 +9,36 @@ const URL = 'https://evening-anchorage-3159.herokuapp.com/api/'; templateUrl: './simple-demo.html' }) export class SimpleDemoComponent { - public uploader:FileUploader = new FileUploader({url: URL}); - public hasBaseDropZoneOver:boolean = false; - public hasAnotherDropZoneOver:boolean = false; + + uploader:FileUploader; + hasBaseDropZoneOver:boolean; + hasAnotherDropZoneOver:boolean; + response:string; + + constructor (){ + this.uploader = new FileUploader({ + url: URL, + disableMultipart: true, // 'DisableMultipart' must be 'true' for formatDataFunction to be called. + formatDataFunctionIsAsync: true, + formatDataFunction: async (item) => { + return new Promise( (resolve, reject) => { + resolve({ + name: item._file.name, + length: item._file.size, + contentType: item._file.type, + date: new Date() + }); + }); + } + }); + + this.hasBaseDropZoneOver = false; + this.hasAnotherDropZoneOver = false; + + this.response = ''; + + this.uploader.response.subscribe( res => this.response = res ); + } public fileOverBase(e:any):void { this.hasBaseDropZoneOver = e; diff --git a/demo/src/doc.md b/demo/src/doc.md index 9954d39..eacd89a 100644 --- a/demo/src/doc.md +++ b/demo/src/doc.md @@ -25,6 +25,9 @@ import { FileSelectDirective, FileDropDirective, FileUploader } from 'ng2-file-u 1. `url` - URL of File Uploader's route 2. `authToken` - auth token that will be applied as 'Authorization' header during file send. 3. `disableMultipart` - If 'true', disable using a multipart form for file upload and instead stream the file. Some APIs (e.g. Amazon S3) may expect the file to be streamed rather than sent via a form. Defaults to false. + 4. `itemAlias` - item alias (form name redefenition) + 5. `formatDataFunction` - Function to modify the request body. 'DisableMultipart' must be 'true' for this function to be called. + 6. `formatDataFunctionIsAsync` - Informs if the function sent in 'formatDataFunction' is asynchronous. Defaults to false. ## FileDrop API @@ -37,3 +40,4 @@ import { FileSelectDirective, FileDropDirective, FileUploader } from 'ng2-file-u - `fileOver` - it fires during 'over' and 'out' events for Drop Area; returns `boolean`: `true` if file is over Drop Area, `false` in case of out. See using in [ts demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.ts) and [html demo](https://github.com/valor-software/ng2-file-upload/blob/master/demo/components/file-upload/simple-demo.html) + - `onFileDrop` - it fires after a file has been dropped on a Drop Area; you can pass in `$event` to get the list of files that were dropped. i.e. `(onFileDrop)="dropped($event)"` \ No newline at end of file diff --git a/demo/src/tsconfig.json b/demo/src/tsconfig.json index 2f97dc9..34d32dd 100644 --- a/demo/src/tsconfig.json +++ b/demo/src/tsconfig.json @@ -3,7 +3,7 @@ "declaration": false, "emitDecoratorMetadata": true, "experimentalDecorators": true, - "noEmitHelpers" :true, + "noEmitHelpers": false, "lib": ["es6", "dom"], "types": [ "jasmine",