订阅无法触发子组件的文件输入上的click()

时间:2018-11-14 17:30:09

标签: angular rxjs

请考虑其模板包含文件输入的组件。可以通过调用公共open()方法来打开输入,该方法触发对输入nativeElement的点击。

@Component({
  selector: 'child',
  template: '<input type="file" #input/>',
})
export class ChildComponent {
  @ViewChild('input')
  public input: ElementRef;

  public open(): void {
    console.log('OPENING THE FILE INPUT');
    this.input.nativeElement.click();
  }
}

ChildComponentParentCompenent中被调用,它在多个上下文中调用ChildComponent.open(),如下所示:

@Component({
  selector: 'parent',
  template: '<child></child>',
})
export class ParentComponent {
  @ViewChild(ChildComponent)
  public child: ChildComponent;

  constructor( private parentService: ParentService ) {
  }

  public openChildInput(): void {
    // This works.
    // Output:
    //  OPENING THE FILE INPUT
    //  The file input opens

    this.child.open();
  }

  public waitAndOpenChildInput(): void {
    parentService.wait()
      .subscribe( () => {
        // This does not work.
        // Output:
        //  "OPENING THE FILE INPUT"
        //  The file input DOES NOT open...
        this.child.open();
      })
  }
}

在两种情况下,调用open()方法似乎都可以工作(如console.log所示);但是从订阅中调用时,文件输入似乎不愿意打开自己。

任何想法为何? 预先感谢...

1 个答案:

答案 0 :(得分:3)

出于安全原因,现代浏览器无法以编程方式在文件输入上调用date_counter事件-除非,该事件发生在用户互动期间。否则,网站和广告可能会通过文件对话框向用户发送垃圾邮件,而无需他们与页面进行交互,例如让他们在不知不觉中上传文件。

使用Observable的问题在于,如果它是异步的(即,使用click调度程序时),则您离开用户交互上下文,浏览器将不会打开文件对话框。

您只能通过使Observable同步(实际上,几乎所有预设的Observable都是同步的)来解决此问题。如果您有一个HTTP请求,这将是不可能的,您必须进行look for alternatives for opening the file dialog(尽管我不确定其中任何一个是否可以在您的设置中使用)。

Here is an GitHub issue与您的问题类似,有一个解释:

  

因此[由于异步],从Chrome的角度来看,click()调用[...]并非由用户事件触发,因此被忽略。