【问题标题】:Angular2 Output EventEmitter.emit not workingAngular2输出EventEmitter.emit不工作
【发布时间】:2018-10-20 16:18:21
【问题描述】:

我创建了具有拖放功能的文件上传指令。奇怪的部分是,当从打开的窗口中选择文件时,它正在工作,但当文件被拖放时,即使整个逻辑相同并且变量具有相同的值,它也不工作。 下面的代码不会发出事件,即使代码运行到 .emit 行

    @Output() public fileSelect: EventEmitter<File> = new EventEmitter<File>();

    @HostListener('drop', ['$event'])
  public onDrop(event: any): void {
    console.log("drop");
    const transfer = this.getDataTransfer(event);

    if (!transfer) {
      return;
    }

    this.preventAndStop(event);
    this.emitFileOver(false);

    this.handleFiles(transfer.files);
  }

    private emitFileSelect(file: any): void {
    this.fileSelect.emit(file);
  }

拖放和从窗口中选择文件的区别在于监听器。下面的代码打开选择窗口,当文件被选中时,handleFiles 被调用,就像在拖放事件中一样。

@HostListener('change', ['$event'])
  public onChange(event) {
    console.log("change");
    this.handleFiles(event.srcElement.files);
  }

您可以看到两个侦听器都使用相同的参数值调用 handleFiles(我对其进行了调试)。 整个代码:

   import { FileUploadState, FileOptions } from './file-drop.models';
import {
  Directive,
  EventEmitter,
  ElementRef,
  HostListener,
  Input,
  Output
} from '@angular/core';

@Directive({ selector: '[pdFileDrop]' })
export class FileDropDirective {
  @Output()
  public fileOver: EventEmitter<boolean> = new EventEmitter<boolean>();
  @Output()
  public fileUploadState: EventEmitter<FileUploadState> = new EventEmitter<
    FileUploadState
    >();
  @Output() public fileSelect: EventEmitter<File> = new EventEmitter<File>();
  @Input() public options: FileOptions;

  private element: ElementRef;

  public constructor(element: ElementRef) {
    this.element = element;
    this.element.nativeElement.setAttribute('multiple', 'multiple');
  }

  @HostListener('dragover', ['$event'])
  public onDragOver(event: any): void {
    console.log("dragOver");
    const transfer = this.getDataTransfer(event);

    if (!this.haveFiles(transfer.types)) {
      return;
    }

    transfer.dropEffect = 'copy';
    this.preventAndStop(event);
    this.emitFileOver(true);
  }

  @HostListener('dragleave', ['$event'])
  public onDragLeave(event: any): void {
    console.log("dragLeave");
    if (event.currentTarget === (this as any).element[0]) {
      return;
    }

    this.preventAndStop(event);
    this.emitFileOver(false);
  }

  @HostListener('drop', ['$event'])
  public onDrop(event: any): void {
    console.log("drop");
    const transfer = this.getDataTransfer(event);

    if (!transfer) {
      return;
    }

    this.preventAndStop(event);
    this.emitFileOver(false);

    this.handleFiles(transfer.files);
  }

  @HostListener('change', ['$event'])
  public onChange(event) {
    console.log("change");
    this.handleFiles(event.srcElement.files);
  }

  ngOnInit() {
    console.log("Observers: " + this.fileSelect.observers.length);
  }

  private handleFiles(files: any) {
    console.log("handleFiles");
    // check all files
    for (let i = 0; i < files.length; i++) {
      console.log(i);
      const fileUploadState = <FileUploadState>{};
      const isFileTypeSupported = this.isFileTypeSupported(files[i].name);
      const isFileSizeAllowed = this.isFileSizeAllowed(files[i].size);

      fileUploadState.fileTypeNotAllowedError = !isFileTypeSupported;
      fileUploadState.fileSizeToBigError = !isFileSizeAllowed;
      fileUploadState.error = !isFileTypeSupported || !isFileSizeAllowed;
      fileUploadState.done = false;
      fileUploadState.file = files[i];
      this.emitFileSelect(fileUploadState);
    }
  }

  private emitFileOver(isOver: boolean): void {
    this.fileOver.emit(isOver);
  }

  private emitFileSelect(file: any): void {
    this.fileSelect.emit(file);
  }

  private isFileTypeSupported(fileName: string): boolean {
    if (!this.options) {
      return true;
    } else if (!this.options.supportedFilesTypes) {
      return true;
    } else {
      return (
        this.options.supportedFilesTypes.indexOf(
          this.getFileExtensionFromFileName(fileName).toLowerCase()
        ) !== -1
      );
    }
  }
  private isFileSizeAllowed(fileSize: number) {
    if (!this.options) {
      return true;
    } else if (!this.options.maxUploadSizeInMb) {
      return true;
    } else {
      return fileSize / 1000000 <= this.options.maxUploadSizeInMb;
    }
  }

  private getDataTransfer(event: any | any): DataTransfer {
    return event.dataTransfer
      ? event.dataTransfer
      : event.originalEvent.dataTransfer;
  }

  private preventAndStop(event: any): void {
    event.preventDefault();
    event.stopPropagation();
  }
  private getFileExtensionFromFileName(fileName: string): string {
    return fileName.substr(fileName.lastIndexOf('.') + 1);
  }
  private haveFiles(types: any): boolean {
    if (!types) {
      return false;
    }

    if (types.indexOf) {
      return types.indexOf('Files') !== -1;
    }

    if (types.contains) {
      return types.contains('Files');
    }

    return false;
  }
}

发出的事件被组件捕获。在选择文件的情况下,代码执行将按预期运行到此 fileSelect($event) 函数中(见下文),在 drg&drop 的情况下,代码执行在 emitFileSelect 函数的 .emit 行结束(见上文)。

<label pdFileDrop [options]="options" (change)="fileSelect($event)">
          <input type="file" />
        </label>

fileSelect($event) {
const that = this;
const reader = new FileReader();
const image = $event.target.closest('.box').querySelectorAll('img')[0];
$event.target.closest('.box').classList.add('thumb-shown');

reader.onload = function (event) {
  if (event && event.target && event.target['result']) {
    image.src = event.target['result'];
    that._file.id = that.id;
    that._file.src = event.target['result'];
    that.attachmentForm.controls['fileName'].patchValue(
      $event.target.files[0].name
    );
    that._file.description = $event.target.files[0].name; //fileName;
    that._file.rotation = that.rotateDeg;
    that._file.thumbnail = image.src;
    that._file.fileType = that.getFileType(image.src);
  }
};

可能阻止浏览器重定向到拖放的文件路径并在浏览器中显示文件的 preventAndStop 函数也阻止了 .emit 事件?更新: preventAndStop 函数不会阻塞 event.emit。

【问题讨论】:

    标签: angular eventemitter emit


    【解决方案1】:

    您错误地使用了 Output EventEmitter:

    尝试(fileSelect)="fileSelect($event)" 而不是(change)="fileSelect($event)

    【讨论】:

    • 我相信您应该将@JoshuaChan 标记为最佳答案,因为他是正确的。
    【解决方案2】:

    所以问题出在

    <label pdFileDrop [options]="options" (change)="fileSelect($event)">
              <input type="file" />
            </label>
    

    我需要监听 EventEmitter,而不是更改事件。所以正确的应该是:

    <label pdFileDrop [options]="options" (fileSelect)="fileSelect($event)">
              <input type="file" />
            </label>
    

    并且需要一些代码适配,但最终 d&d 正在工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-04-12
      • 2017-11-23
      • 2017-03-03
      • 2016-08-15
      • 2017-04-29
      • 2017-09-20
      • 1970-01-01
      相关资源
      最近更新 更多