The error "Apply apply" is already running, although I do not explicitly call $ apply ()

I am creating a directive that helps with downloading a CSV file. For this, I use <input type="file" ng-hide="true"/> and my own JavaScript FileReader() . Everything works fine when I select a file using native input , but I tried to customize the file control using my own Browse button. The problem is that when I try to do this, I get that the value of $ apply is already running.

Here is my directive

 app.directive('skUploader', function ($timeout) { return { restrict: 'A', replace: true, template: '<div>\ <input type="file" class="uploadControl" ng-hide="false" />\ <input type="text" ng-model="selectedFile" />\ <button type="button" class="btnPlain" ng-click="triggerBrowse()">Browse</button>\ <button type="button" class="btnOrange fRight" ng-click="uploadCSV()">Upload</button>\ <button type="button" class="btnPlain fRight" ng-click="cancel()">Cancel</button>\ </div>', link: function (scope, elem, attr, ctrl) { var uploadControl = elem.find('input[type=file]'); var payload = null; var type = attr.skUploader; scope.selectedFile = null; scope.uploadCSV = function () { $timeout(function () { alert('Upload Successful'); }, 3000); } scope.cancel = function () { payload = null; scope.selectedFile = null; scope.model.showUploadPanel = false; } uploadControl.on('change',function () { var fileHandle = uploadControl[0].files[0]; var reader = new FileReader(); var buffer; scope.selectedFile = fileHandle.name; reader.onload = function(){ buffer = reader.result; payload = parseCSV(buffer); if (payload) { // Make API call if (type == 'mapping') { console.log(payload); } else { } } } if (fileHandle.name.indexOf('.csv') > 0) { reader.readAsText(fileHandle); } else { } }); function parseCSV(buff){ var entries = []; entries = buff.split(/\n/); var json = []; if (type == 'mapping') { var formatter = { iRowNumber: null, SourceName: null, DestName: null }; } else if (type == 'passwords') { var formatter = { iRowNumber: null, SourceCreds: { EmailAddress: null, Username: null, Pwd: null } }; } else { return null; } for(var i = 1; i < entries.length - 1; i++){ var split = entries[i].split(','); var obj = angular.copy(formatter); var j = 0; angular.forEach(formatter, function (value, key) { if (key == 'iRowNumber') { obj[key] = i; } else if (key == 'SourceCreds') { obj[key] = { EmailAddress: split[0], Username: split[1], Pwd: split[2] }; }else{ obj[key] = split[j]; j++; } }); json.push(obj); } return json; } scope.triggerBrowse = function () { uploadControl.trigger('click'); // THIS IS WHAT CAUSES THE ERROR } } }; }); 

When I use the browse button on trigger('click') , uploadControl, Angular spits out an error

 Error: [$rootScope:inprog] $apply already in progress 

But I do not use scope.$apply() anywhere, so I can not understand the problem. It should just fire the click event on <input type="file"/> , which should trigger its own OS file explorer.

Update

Maybe this is due to this problem ?

Update 2

After some more research, I found this Git problem in which vojta (the core of AngularJS dev) replied that we needed to wrap the event in $timeout , I did it and it really worked! Can someone explain to me why this is necessary in detail? Thanks you

+7
angularjs
source share
1 answer

When you make changes to an area without using Angular functions (for example, using a jQuery event handler instead of ngClick ), it gets very angry. Sometimes he simply ignores your changes until another option is launched, and sometimes you catch him at a particularly angry moment, when he is already busy with other things, and he will give you your mistake.

To be Angular friendly, you need to use your event system to update the scope. If you cannot do this, you have a way of saying that you are making changes so that he can handle these changes in his own schedule. Thus $timeout is an Angular friendly version of JavaScript timeout integrated with the update loop. A call without a duration parameter means that "the next time you are ready for changes in the area, do it."

Calling $apply itself is not a good idea, by the way, just use $timeout .

+24
source share

All Articles