0

I have a drop down menu using ng-select, and I want a file upload dialog to appear whenever an option is selected from the menu. The menu options are for different file types. So for example if I select the "pdf" option from the menu, I want my file upload dialog to white out everything except for pdf files.

I wasn't able to figure out how to do this inside my ng-select tag so I ended up making a hidden input html tag in my template:

  <ng-select  class="regular dashboardButtonUI" style="text-align-last: center;" [items]="loaders"
  bindLabel="display_name" placeholder="Upload Annotation" [(ngModel)]="selectedUpload" (change)="upload(selectedUpload)">
  </ng-select>

  <input hidden type="file" #uploader (change)="onFileChange($event.target.files)" name="uploader" accept="{{'.'+ selectedLoader?.format}}"/>

In my component I have

@ViewChild('uploader', {static: false}) uploader: ElementRef;
selectedLoader: Loader=null;
fileToUpload: File = null;

...

upload(selectedUpload: Loader){
    this.selectedLoader=selectedUpload;
    setTimeout(() =>     this.uploader.nativeElement.click(), 1000);
}

onFileChange(files: FileList){
   this.fileToUpload = files.item(0);
}

The problem is this won't work if I don't use setTimeout. If I just call click() without the timeout, all file types get whited out on my file upload dialog. It's almost as if in my template, my accept attribute didn't get the updated selectedLoader.format (which by the way is null by default).

I also find it strange that when I tried to use a while loop like so:

var count: number = 0;
    while(selectedUpload.format !==this.uploader.nativeElement.getAttribute('accept') && count<100000 ){
     console.log("bowowow");
      ++count;
   }

The accept attribute of my input tag still doesn't get updated, even though my while loops takes just as long if not more than my setTimeout. Why is that?

Finally, sometimes I'll get this error message "File chooser dialog can only be shown with a user activation." in my console, but only when I use a while loop that runs for a very long time.

I'm glad that using setTimeout seems to work, but I have no idea how and I also am feel hesitant about using some arbitrary time interval rather than being actually sure that the accept attribute of the input tag is the value that the user picked from the ng select drop down menu.

Shisui
  • 1,051
  • 1
  • 8
  • 23
  • If you change the `setTimeout` from 1000 to 0, will it still work? I think it has something to do with the js event loop. This is because js is single threaded and Angular change detection seems to run after the current event is processed. So when `this.selectedLoader=selectedUpload;` runs, the change detection hasn't run yet so the view won't get updated. – Antediluvian Dec 02 '19 at 04:16
  • @Antediluvian wow yeah when I change it to 0 it still works. That's crazy. – Shisui Dec 02 '19 at 04:26
  • 1
    The fact that it still works means it has nothing to do with the timing. It is just that the current event queue is busy and Angular hasn't got a chance to do the change detection. But if you do `setTimeout`, js will put whatever inside it to the end of the event queue. That way Angular can do the change detection and update the view before the popup comes out. – Antediluvian Dec 02 '19 at 04:39

0 Answers0