den*_*iii 7 file-upload angularjs
我有一个
<input type="file" id="aircraftList" name="aircraftList" file-upload multiple/>
Run Code Online (Sandbox Code Playgroud)
绑定到指令
angular.module("app.directives").directive('fileUpload', function () {
return {
scope: true,
link: function (scope, el, attrs) {
el.bind('change', function (event) {
scope.$emit("fileSelected", { files: event.target.files, field: event.target.name });
});
}
};
});
Run Code Online (Sandbox Code Playgroud)
我在控制器中捕获此事件:
$scope.$on("fileSelected", function (event, args) {
$scope.$apply(function () {
switch (args.field) {
case "aircraftList":
self.attachments.aircraftList = args.files;
break;
default:
break;
}
});
});
Run Code Online (Sandbox Code Playgroud)
出于某种原因,这在Chrome和Firefox中运行良好,但在IE11中失败并出现以下错误:
如果我没有把$ apply,chrome没有更新视图,但IE是.如果我把$ apply,Chrome工作完美且IE中断.
谁知道这里出了什么问题以及为什么会出错?
实际上,chrome与FFjavascript引擎相比,IE11javascript引擎非常快.
因此,当
$scope.$on("fileSelected"在chrome&中 触发时FF,前一$digest循环将在$scope.$apply执行时完成,因此没有错误.由于$digest在此阶段没有 循环运行,我们需要另一个$digest循环来更新视图,有了$scope.$apply这个和没有这个的帮助,视图将不会更新.由于
IE在上面的相同场景中相对较慢,$scope.$apply因为$digest当前正在运行一个循环, 因此抛出错误.因此,在没有的情况下$scope.$apply,视图将在运行$digest周期的帮助下得到更新.
当我们$timeout按照其他用户的说法使用时,它会在当前$digest周期完成后开始执行,并确保用另一个$digest循环更新视图.
希望它会澄清你:-)
$scope.$on("fileSelected", function (event, args) {
$timeout(function () {
switch (args.field) {
case "aircraftList":
self.attachments.aircraftList = args.files;
break;
default:
break;
}
});
});
Run Code Online (Sandbox Code Playgroud)
首先,您是$apply从已经执行的$digest周期内调用的。Chrome/FF 可能适合您,但这实际上取决于您的运气。实际上,您受到用户 PC 性能的支配。$digest每当传输事件时,Angular 总是会触发它自己的周期。你的$scope.$emit意志在这里被触发$digest。
不过,这里有一些问题,这些问题将使一切陷入困境,并会导致更多此类问题。$digest通常,除非您响应从 Angular 外部触发的事件,否则不需要触发循环。
您的指令file-uploader似乎过于依赖于您的视图模型 - 它甚至告诉控制器应该将返回的数据存储在哪个字段中。记住,这是控制器的工作!我对您的代码进行了一些更改,以确保不需要有两个同时的$apply周期,这消除了您的问题,并且还稍微整理了代码。
我已更改指令以使用双向数据绑定,而不是通过 rootscope 发出事件 - 对性能和功能封装有很大的改进。
app.directive('testUploader', [function() {
return {
scope: {
ngModel: '='
},
link: function(scope, el) {
el.bind('change', function(event) {
if (event.target.files && event.target.files.length > 0) {
angular.forEach(event.target.files, function (newFile) {
scope.ngModel.push(newFile);
});
scope.$apply();
}
});
}
};
}]);
Run Code Online (Sandbox Code Playgroud)
这极大地简化了控制器,现在不需要处理客户端事件 - 它只是在视图模型和服务器上的任何底层数据模型之间进行调解
app.controller("testctrl", ['$scope', function($scope) {
$scope.data = {
aircraftList: []
};
}]);
Run Code Online (Sandbox Code Playgroud)
请参阅此处的工作 JSFiddle:https ://jsfiddle.net/z2yLad92/27/
希望这可以帮助。
| 归档时间: |
|
| 查看次数: |
1381 次 |
| 最近记录: |