angularjs - ng2 - Angular: $ aplica ya en progreso en IE11, pero no en FF y Chrome
upload file angular 6 (5)
tengo un
<input type="file" id="aircraftList" name="aircraftList" file-upload multiple/>
obligado a una directiva
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 });
});
}
};
});
Capté este evento en un controlador:
$scope.$on("fileSelected", function (event, args) {
$scope.$apply(function () {
switch (args.field) {
case "aircraftList":
self.attachments.aircraftList = args.files;
break;
default:
break;
}
});
});
Por alguna razón, esto funciona perfectamente en Chrome y Firefox, pero falla en IE11 con el siguiente error:
Si no pongo $ apply, Chrome no actualiza la vista, pero IE sí. Si pongo $, Chrome funciona perfecto y IE se rompe.
¿Alguien sabe qué y por qué sale mal aquí?
Puede aplicar el alcance al verificar primero
(!$scope.$$phase) ? $scope.$apply() : null;
No aplicará alcance si ya está en progreso.
Usted se metió en este problema ya que su código intenta desencadenar el ciclo de resumen antes de que uno se haya completado y que esté enfrentando solo en IE probablemente debido a la naturaleza lenta de IE. entonces mi idea es usar $ scope. $ evalAsync
$scope.$evalAsync(function () {
switch (args.field) {
case "aircraftList":
self.attachments.aircraftList = args.files;
break;
default:
break;
}
});
$ scope. $ evalAsync agregará la función suministrada a una cola que será drenada al comienzo del siguiente ciclo en un ciclo de resumen.
Espero que esto funcione para ti.
Gracias
No sé por qué ambos navegadores se comportan de manera diferente. Pero sé que para deshacerse de este error y hacerlo funcionar
Usaste $ apply (). Si obtiene el error $ rootScope: inprog , significa que ya se está ejecutando un ciclo de resumen. Para evitar este error, ajuste su función $ apply en una condición de tiempo de espera excedido.
Me gusta esto,
$scope.$on("fileSelected", function (event, args) {
$timeout(function () {
$scope.$apply(function () {
switch (args.field) {
case "aircraftList":
self.attachments.aircraftList = args.files;
break;
default:
break;
}
});
},500);
});
Espero que esto funcione para ti.
En realidad, los motores de JavaScript chrome
y FF
son muy rápidos en comparación con el motor de JavaScript IE11
.
Por lo tanto, cuando
$scope.$on("fileSelected"
se activa enchrome
&FF
, el bucle$digest
anterior se completará en el momento de$scope.$apply
Se ejecuta$scope.$apply
y, por lo tanto, no hay errores. Como no hay$digest
ciclo se está ejecutando en esta etapa, necesitamos otro$digest
ciclo de$digest
para actualizar la vista con la ayuda de$scope.$apply
y sin esto, la vista no se actualizará.Como
IE
es comparativamente lento en el mismo escenario anterior,$scope.$apply
arroja un error ya que hay un bucle$digest
está ejecutando actualmente. Por lo tanto, sin$scope.$apply
, La vista se actualizará con la ayuda del ciclo$digest
actual.
Cuando usamos $timeout
como dicen otros usuarios, se ejecutará una vez que se complete el ciclo actual de $digest
y asegurándose de actualizar la vista con otro ciclo de $digest
.
Espero que te aclare :-)
$scope.$on("fileSelected", function (event, args) {
$timeout(function () {
switch (args.field) {
case "aircraftList":
self.attachments.aircraftList = args.files;
break;
default:
break;
}
});
});
En primer lugar, está llamando a $apply
desde un ciclo de $digest
ya se está ejecutando. Chrome / FF puede estar bien para ti, pero eso depende de la suerte de tu parte. Realmente en esto estás a merced del rendimiento de la PC del usuario. Angular siempre activará su propio ciclo de $digest
cuando esté transmitiendo eventos. Su $scope.$emit
desencadenará $digest
aquí.
Aquí tienes algunos problemas que van a atar todo en nudos y causarán más problemas de este tipo. Normalmente, no debería haber necesidad de activar un ciclo de $digest
menos que responda a eventos desencadenados desde fuera de Angular.
Su carga de file-uploader
directivas parece demasiado dependiente de su modelo de visualización, incluso le está diciendo al controlador en qué campo debe almacenar los datos devueltos. Recuerde, ese es el trabajo de los controladores. He cambiado un poco el código para asegurarme de que no hay necesidad de tener dos ciclos simultáneos de $apply
, lo que elimina su problema y también ordena un poco el código.
Cambié la directiva para utilizar el enlace de datos bidireccional en lugar de emitir eventos a través del ramoscopio: gran mejora del rendimiento y encapsulación de la funcionalidad.
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();
}
});
}
};
}]);
Esto simplifica enormemente el controlador que ahora no tiene necesidad de manejar eventos de clientes; simplemente media entre el modelo de vista y cualquier modelo de datos subyacente en su servidor.
app.controller("testctrl", [''$scope'', function($scope) {
$scope.data = {
aircraftList: []
};
}]);
Ver JSFiddle trabajando aquí: https://jsfiddle.net/z2yLad92/27/
Espero que esto ayude.