Angular 1 infinite ng-click

Angular 1 infinite ng-click

Never thought I would be back here talking about angular. But here we are nonetheless. For the last year I have been in charge of a project that has been the literal definition of a disaster. Besides the long story about why, I just wanted to take a moment to talk about a particular issue that randomly started affecting uploading images and was really hard to find. I wanted to reveal why this occurs just in case anyone is still trapped in angular 1 land and has ran across this hard to search for issue. So let's get started.

Given the following HTML

<body>
    <div ng-click="doUpload()">
      <input id="fileupload" type="file" hidden multiple />
      <em class="fa fa-file-image-o fa-2x"></em>
    </div>
</body>

And given this javascript, and assuming this code is in a controller of some kind:

const input = document.querySelector('input#fileupload');

input.onchange(()=>{
  //save the data
});

$scope.doUpload = () => {
  $timeout(() =>{
    input.click();
  });
}

What's wrong with this?

First lets walk through what will happen. When clicking the div that includes the ng-click the doUpload function will fire. This will then trigger a click action on the input field that is currently hidden.

Seems straightforward enough...

You might assume that when the div is clicked, there is a chance that the ng-click is triggered and maybe a chance of the input's click event to also trigger. Resulting in 2 events occuring instead of one.

That, while a valid assumption, would be false.

Instead you get an infinite loop of ng-click triggers. Originally I thought that maybe the controller was being loaded on every digest. But that wasn't the case. Googling ng-click infinite trigger doesn't bring up any results for this issue. You do run across various accounts of people having issues with ng-click firing twice. I only found the answer in a comment to a solution of one of those 2 triggering solutions which was a lucky find.

The easiest way to fix this issue is to move the input field outside of the clickable div.

<body>
    <input id="fileupload" type="file" hidden multiple />
    <div ng-click="doUpload()">
      <em class="fa fa-file-image-o fa-2x"></em>
    </div>
</body>

It doesn't need to be nested inside - since it is hidden - and could technically be placed anywhere on the page.

I hope this helps others that may have a disaster project that needs maintaining like I do. Above all, hopefully you don't have this issue in such project at all. Although if you are here, I am sorry for your loss.