0

I've created a file input to open a video. And I'd like to display that video input at the condition that my_variable exists. This is what the HTML looks like:

<input type="file" (change)="handleFileInput($event)" accept="video/mp4">
<div *ngIf="my_variable">
  <video id="video" width="200" height="200" src="{{ my_variable.path }}">
  </video>
</div>

The (change) event is called whenever the user chooses a video. And my function handleFileInput is supposed to update my_variable like this:

handleFileInput(event: any) {
    this.my_variable = event.target.files.item(0);
    this.video = document.getElementById('video') as HTMLInputElement;
    // do other stuff that requires this.video variable
}

My problem is that the this.video variable is null. Actually, since the change event is not finished yet, the ng if condition in the DOM does not update the view, and then, my video input is never created. Hence the fact that this.video is null at this point. But I don't know how to solve this issue.

I didn't find anything on Stack Overflow, I tried to set a timeout when doing a document.getElementById('video'). For example:

setTimeout(() => {
    this.video = document.getElementById('video') as HTMLInputElement;
    // do other stuff that requires this.video variable
      }, 1000); 

It actually worked, but I wish I could find a clearer solution. Could you please help me ? Thank you

marehihd
  • 1
  • 1

2 Answers2

1

Having the video tag in the HTML DOM and toggling it with a variable using the ngIf, what you are doing is that you are creating a cylic dependency because of which this.video is null since it is waiting for the change event handler to complete it's work.What you need to do, that you add the video tag dynamically

<input type="file" (change)="handleFileInput($event)" accept="video/mp4">
<div #videoTagContainer></div>
@ViewChild('videoTagContainer') public videoTagContainer: ElementRef;


handleFileInput(event: any) {
    this.my_variable = event.target.files.item(0);
    let parentElement = this.videoTagContainer.nativeElement;

    if(parentElement.firstChild) 
        parentElement.removeChild(parentElement.firstChild);

    let videoElement = document.createElement('video') as HTMLInputElement;
    videoElement.id = 'video';
    videoElement.width = '200px';
    videoElement.height = '200px';
    videoElement.src = this.my_variable.path;

    parentElement.appendChild(videElement);
    // do other stuff that requires this.video variable
}
Malhar
  • 163
  • 3
  • 13
  • Hi, thank you for your help, I just heard that using id in compoments were not recommended, instead it'd be better to use the @viewChild annotation, but I assume your solution is not possible with this annotation right ? – marehihd Jan 02 '20 at 14:04
  • yes you can use @ViewChild annotation with my approach. Instead of getting the parentElement via getElementById, get it via the templateReference variable. – Malhar Jan 02 '20 at 15:59
  • I have updated my answer to use ViewChild. Can you please upvote my answer if you find it useful. Thanks, I'm glad to help. – Malhar Jan 02 '20 at 16:20
1

dont use *ngIf

<div [style.display]="my_variable ? 'none' : 'block'">
  <video ....>
  </video>
</div>
feyzullahyildiz
  • 456
  • 4
  • 11
  • You should not use **id** in a component. Use ViewChild annotation instance of id – feyzullahyildiz Jan 02 '20 at 11:47
  • Hi thank you for your help but I still have an error in my console when hiding the div because I use my_variable as a path to my video... (the 'src' attribute) – marehihd Jan 02 '20 at 13:31
  • Is using id in a component not recommended ? – marehihd Jan 02 '20 at 13:32
  • @marehihd - What error do you get when hiding the `div`? – ConnorsFan Jan 02 '20 at 16:15
  • if you use id in a component for an Element. You cannot use that component more then one. If your have same id element more then once you will always get the first one via using document.getElementById('foo') `
    A
    B
    ` You cannot get second div never in any component while first component is alive. Use ViewChild https://angular.io/api/core/ViewChild
    – feyzullahyildiz Jan 03 '20 at 08:59