angularjs – 即使我没有显式调用$apply(),也会’获取’$apply已在进行中’错误

前端之家收集整理的这篇文章主要介绍了angularjs – 即使我没有显式调用$apply(),也会’获取’$apply已在进行中’错误前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在创建一个有助于上传CSV文件的指令.我正在使用< input type =“file”ng-hide =“true”/>和本机 JavaScript FileReader()来做到这一点.当我使用本机输入选择文件时,一切正常,但我尝试使用自己的“浏览”按钮自定义文件控件.问题是,当我尝试这样做时,我得到$apply已经在进行中错误.

这是我的指示

  1. app.directive('skUploader',function ($timeout) {
  2. return {
  3. restrict: 'A',replace: true,template: '<div>\
  4. <input type="file" class="uploadControl" ng-hide="false" />\
  5. <input type="text" ng-model="selectedFile" />\
  6. <button type="button" class="btnPlain" ng-click="triggerBrowse()">Browse</button>\
  7. <button type="button" class="btnOrange fRight" ng-click="uploadCSV()">Upload</button>\
  8. <button type="button" class="btnPlain fRight" ng-click="cancel()">Cancel</button>\
  9. </div>',link: function (scope,elem,attr,ctrl) {
  10.  
  11. var uploadControl = elem.find('input[type=file]');
  12. var payload = null;
  13.  
  14. var type = attr.skUploader;
  15. scope.selectedFile = null;
  16.  
  17. scope.uploadCSV = function () {
  18. $timeout(function () {
  19. alert('Upload Successful');
  20. },3000);
  21. }
  22.  
  23. scope.cancel = function () {
  24. payload = null;
  25. scope.selectedFile = null;
  26. scope.model.showUploadPanel = false;
  27.  
  28. }
  29.  
  30. uploadControl.on('change',function () {
  31. var fileHandle = uploadControl[0].files[0];
  32. var reader = new FileReader();
  33. var buffer;
  34.  
  35. scope.selectedFile = fileHandle.name;
  36.  
  37. reader.onload = function(){
  38. buffer = reader.result;
  39.  
  40. payload = parseCSV(buffer);
  41.  
  42. if (payload) {
  43. // Make API call
  44. if (type == 'mapping') {
  45. console.log(payload);
  46. } else {
  47.  
  48. }
  49. }
  50. }
  51.  
  52. if (fileHandle.name.indexOf('.csv') > 0) {
  53. reader.readAsText(fileHandle);
  54. } else {
  55.  
  56. }
  57.  
  58. });
  59.  
  60. function parseCSV(buff){
  61.  
  62. var entries = [];
  63. entries = buff.split(/\n/);
  64.  
  65. var json = [];
  66.  
  67.  
  68. if (type == 'mapping') {
  69. var formatter = {
  70. iRowNumber: null,SourceName: null,DestName: null
  71. };
  72. } else if (type == 'passwords') {
  73. var formatter = {
  74. iRowNumber: null,SourceCreds: {
  75. EmailAddress: null,Username: null,Pwd: null
  76. }
  77. };
  78. } else {
  79. return null;
  80. }
  81.  
  82.  
  83. for(var i = 1; i < entries.length - 1; i++){
  84. var split = entries[i].split(',');
  85.  
  86. var obj = angular.copy(formatter);
  87.  
  88. var j = 0;
  89. angular.forEach(formatter,function (value,key) {
  90. if (key == 'iRowNumber') {
  91. obj[key] = i;
  92. } else if (key == 'SourceCreds') {
  93. obj[key] = {
  94. EmailAddress: split[0],Username: split[1],Pwd: split[2]
  95. };
  96. }else{
  97. obj[key] = split[j];
  98. j++;
  99. }
  100. });
  101.  
  102. json.push(obj);
  103.  
  104. }
  105.  
  106. return json;
  107.  
  108. }
  109.  
  110. scope.triggerBrowse = function () {
  111. uploadControl.trigger('click'); // THIS IS WHAT CAUSES THE ERROR
  112. }
  113. }
  114. };
  115. });

当我使用“浏览”按钮触发(‘点击’)uploadControl时,Angular会发出错误

  1. 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.

猜你在找的Angularjs相关文章