使用HTML元素事件处理程序访问指令范围

时间:2018-10-26 12:16:12

标签: angular closures angular6

我创建了一个Directive,通过原生HTML拖放功能将元素用作“ dropzone”

指令源

import { Directive, ElementRef, OnInit, Output, EventEmitter, ViewChild } 
from '@angular/core';
import { environment } from 'src/environments/environment';

@Directive({
    selector: '[app-drop-zone]'
})
export class DropzoneDirective implements OnInit {    
    @Output('outbound-listener') outBoundListener = new EventEmitter();    

    constructor(private e: ElementRef) {        
        e.nativeElement.ondrop = this.drop;
        e.nativeElement.ondragover = this.dragOver;
        e.nativeElement.ondragenter = this.dragEnter;
        e.nativeElement.ondragleave = this.dragLeave;            
    }

    ngOnInit(): void { }

    private drop(event: any){ 

        let files: File[] = []; // temprary cache for dropped files

        if (event.stopPropagation) {
           event.stopPropagation(); // Stops some browsers from redirecting.
        }

        event.currentTarget.classList.remove('over');    // remove the 
        dotted background, once user release the content (drop-end)

       // process dropped items
       if(event.dataTransfer.items){
       for(let i = 0; i< event.dataTransfer.items.length; i++){
           if(event.dataTransfer.items[i].kind == "file"){
               files.push(event.dataTransfer.items[i].getAsFile());
           }
       }

       if(files.length > 0){
           this.outBoundListener.emit({ type: 
           environment.component_events.INIT_FILE_UPLOAD, data: files});              
       }
    }
    return false;
 }

 private dragOver(e){
      if(e.preventDefault)
          e.preventDefault();    

      e.dataTransfer.dropEffect = 'move';
      return false;
 }

 private dragEnter(event: any) {     
    event.currentTarget.classList.add('over');    
 }

 private dragLeave(event: any) {    
    event.currentTarget.classList.remove('over');    
 }
}

**请忽略代码格式:-(

问题这是方法“ drop”中的我想访问指令类道具outBoundListener,它是一个EventEmitter,但是我无法通过{{1 }}

任何对此的帮助,将不胜感激。

1 个答案:

答案 0 :(得分:0)

当您从TypeScript代码中调用时,您拥有的绝对应该可以工作,因为TypeScript / ES6 this的语义对于箭头函数而言有些不同。您可以阅读有关here的更多信息,其中有一个专门介绍热混乱的完整部分,this

这里的问题不是this是指所有者或被调用者,而是DOM元素。您可以通过调用console.log(this)函数顶部的drop进行验证。

之所以会出现问题,是因为不是从ES6或TypeScript代码中调用此函数,而是从DOM事件处理程序中调用此函数。要强制其保留this,可以使用bind函数。

constructor(private e: ElementRef) {        
    e.nativeElement.ondrop = this.drop.bind(this);
    e.nativeElement.ondragover = this.dragOver.bind(this);
    e.nativeElement.ondragenter = this.dragEnter.bind(this);
    e.nativeElement.ondragleave = this.dragLeave.bind(this);
}

请注意,this是您的对象实例,现在您要按照the MDN explanation使用所提供的this值创建一个新函数来强制实现这种情况。

替代方法是直接使用箭头功能。

constructor(private e: ElementRef) {        
    e.nativeElement.ondrop = event => this.drop(event);
    e.nativeElement.ondragover = event => this.dragOver(event);
    e.nativeElement.ondragenter = event => this.dragEnter(event);
    e.nativeElement.ondragleave = event => this.dragLeave(event); 
}

这是可行的,因为箭头功能保留了this,如前所述。