the_critic the_critic - 1 month ago 17
TypeScript Question

Two components interfering file events in Angular2

I have two instances of a component called

FileUploadComponent
, whose responsibility is to listen for file events (it's a simple template that contains a form with a file upload button as shown below) and emit those to its hosting component via an
EventEmitter
.

Simple as it seems, when I add two of those components (Comp1, Comp2) into a template, the first instance of the button on the page seems to receive all events even from separate instances of this particular component.

So to visualize:

Comp1 ---------------------- / EventEmitter Fired
Comp2 -- File uploaded ----- / -------


Here you can see that
Comp1
receives an event from subsequent instances of this
FileUploadComponent
, why is that ?

Here are the files:

file_upload_button.component.ts (Component Decorator omitted for brevity)

export class FileUploadButtonComponent {

@Output() filesChanged = new EventEmitter<File[]>();
private _files: File[];

fileUpload(event: FileReaderEvent) {

console.log(this); // !!! ====> this already triggers in the wrong component!

this._files = event.target.files;
this.filesChanged.emit(this._files);
}
}





Template for button:

file_upload_button.html

<form>
<input type="file" multiple name="file" (change)="fileUpload($event)" id="file"/>
</form>





Host template:

some_host.html

// first instance
<file-upload-button (filesChanged)="filesChangedFunc($event)"><file-upload-button>
// second instance
<file-upload-button (filesChanged)="anotherFilesChangedFunc($event)"><file-upload-button>


When I click the second button, the first instance sees itself responsible, the
console.log(...)
in the above code mentions that. Having gone over this code for several hours I have no sane explanation for what is happening here.




PLUNKER:




http://plnkr.co/edit/7jzjL8dRsCFPUMrVb0I9?p=preview

Answer

That's because you have the same id and for respectively on your elements.

You have to use unique id:

app/file_upload_button.component.ts

let uniqueId = 0;

@Component({
  selector: 'file-upload-button',
  templateUrl: 'app/file_upload_button.html',
  styleUrls: [ 'app/file_upload_button.css' ]
})
export class FileUploadButtonComponent {
  id = `file-upload-${uniqueId++}`;

app/file_upload_button.html

<input type="file" [name]="'name' + id" [id]="id" .../>
<label [attr.for]="id" ...

Plunker