我正在创建一个有助于上传CSV文件的指令.我正在使用< input type =“file”ng-hide =“true”/>和本机
JavaScript FileReader()来做到这一点.当我使用本机输入选择文件时,一切正常,但我尝试使用自己的“浏览”按钮自定义文件控件.问题是,当我尝试这样做时,我得到$apply已经在进行中错误.
这是我的指示
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 } } }; });
当我使用“浏览”按钮触发(‘点击’)uploadControl时,Angular会发出错误
Error: [$rootScope:inprog] $apply already in progress
但我没有使用范围.$apply()在任何地方,所以我无法弄清楚问题.它应该只是触发< input type =“file”/>上的click事件.这应该打开OS本机文件资源管理器.
更新
它可能是与this issue相关的东西吗?
更新2
经过一些研究后,我发现this Git issue vojta(一个核心的AngularJS dev)回应说我们需要将事件包装在$timeout中.我这样做了,它确实有效!有人可以向我解释为什么需要这么详细吗?谢谢
当您在不使用Angular函数的情况下更改范围时(例如,使用jQuery click事件处理程序而不是ngClick),它会变得非常脾气暴躁.有时候它会忽略你的变化,直到它再次运行,有时你会在一个特别脾气暴躁的时刻抓住它,因为它已经忙于其他事情并且它会给你带来的错误.
要成为Angular友好的,您需要使用其事件系统来更新范围.如果您不能这样做,您可以告诉它您正在进行更改,以便它可以按照自己的计划处理这些更改.这种方式是$timeout – 与更新循环集成的JavaScript超时的Angular友好版本.在没有持续时间参数的情况下调用它只意味着“下次您准备好更改范围时,请执行此操作.”
顺便说一下,调用$apply自己不是个好主意,只需使用$timeout.