【问题标题】:AngularJS: Referencing DOM nodes in Angular expressions is disallowedAngularJS:不允许在 Angular 表达式中引用 DOM 节点
【发布时间】:2016-11-18 01:36:12
【问题描述】:

尝试将自定义 onchange 处理程序绑定到输入文件元素。收到以下错误:

不允许在 Angular 表达式中引用 DOM 节点!表达式:setRuleFile(element

有什么办法可以解决吗?

谢谢。以下是我的代码的相关摘录。

html:

<input type="file" on-select-file="setRuleFile(element)"/>

控制器:

$scope.setRuleFile = function(element) {
    // Extract selected file name
    var pathArray = element.value.split('\\');
    $scope.data.ruleFileName = pathArray[pathArray.length - 1];  // take only name without path
    $scope.data.ruleFile = element;
}

指令:

angular.module('myModule').directive('onSelectFile', function ($parse) {
    // Triggered when user selects file
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            // Get callback into variable and bind it to onchange handler
            onSelectFileFunc = $parse(attrs.onSelectFile);
//console.log(onSelectFileFunc(scope, {'element': element}));
            element.bind('change', function() { onSelectFileFunc(scope, {'element': element}); } );
        }
    };
})

【问题讨论】:

  • 为什么需要将元素传递给控制器​​?控制器不应该对 dom 有任何了解。此外,您已经在指令中公开了元素。你到底想做什么?
  • @charlietfl:那我该如何提取文件名呢?之后我还需要使用文件阅读器: var reader = new FileReader(); reader.readAsArrayBuffer($scope.data.ruleFile.files[0]);而且,正如您从我的代码中看到的那样, $scope.data.ruleFile = element;如果我不使用元素,我该如何实现?谢谢。
  • 读取指令中的所有文件数据。使用隔离范围绑定方法或模型对象进行更新。所有控制器都应该关心的是数据本身
  • 传递$event而不是dom,并在代码中使用$event.target

标签: javascript angularjs


【解决方案1】:

这是一个如何在 Angular 1.x 中编写文件上传指令的示例:

angular.module('myApp', [])
  .directive('fileUpload', fileUploadDirective);

function fileUploadDirective() {
  function postLink(scope, iElem, iAttrs) {
    iElem.on('change', doStuff);

    // remove DOM event listener when Angular scope is destroyed
    scope.$on('$destroy', function() {
      iElem.off('change', doStuff);
    });

    function doStuff() {
      console.log(iElem[0].files);
    };
  };

  return {
    link: postLink,
    restrict: 'A'
  };
}

...你会像这样在你的 HTML 模板中使用它:

<input type="file" file-upload>

JSFiddle:https://jsfiddle.net/sscovil/o0ysyem5/

这个指令只是使用 jqLit​​e(Angular 的 jQuery 的淡化版本)来为元素添加一个 DOM 事件监听器;和 HTML5 File API 从元素中获取文件对象。

更新

根据 OP 的评论,以下是一个更新的示例,展示了如何使文件对象可用于同一范围内的其他指令。

angular.module('myApp', [])
  .directive('fileUpload', fileUploadDirective);

function fileUploadDirective() {
  var postLink = function(scope, iElem, iAttrs, ngModelController) {
    function updateModel(event) {
      if (iElem[0].files && iElem[0].files.length) {
        var file = iElem[0].files[0];
        ngModelController.$setViewValue(file, event.type);
      }
    };

    iElem.on('change', updateModel);

    scope.$on('$destroy', function() {
      iElem.off('change', updateModel);
    });
  };

  return {
    link: postLink,
    require: 'ngModel',
    restrict: 'A'
  };
}

...你会像这样在你的 HTML 模板中使用它:

<input type="file" ng-model="myFile" file-upload>

JSFiddle:https://jsfiddle.net/sscovil/o0ysyem5/3/

此示例使用ngModelController,而不是将文件直接绑定到作用域。这样做可以让指令的用户通过ng-model 属性决定将文件对象存储在哪个变量中。

【讨论】:

  • 谢谢,但它并不能完全满足我的需要。我需要一个按钮选择来选择文件,另一个按钮 Import 用于读取文件并将其上传到服务器。第一个按钮应该触发存储元素和文件名以供显示,而第二个按钮将使用该元素来读取文件(并发送它)。您如何将指令中的元素传递到存储范围?
  • 该 postLink 函数使用多个参数调用,包括对范围的引用,因此您可以将结果绑定到 doStuff 函数中的范围。更好的方法是要求 ngModel 并通过 ngModelController 更新 $modelValue ...我将在今晚晚些时候发布更新(我现在没钱了)。
  • @jazzblue 我已经更新了我的答案,以说明如何使用ngModel 将上传的文件对象存储为变量。希望有帮助!
猜你喜欢
  • 2016-04-19
  • 2014-07-13
  • 1970-01-01
  • 2014-07-01
  • 2015-03-07
  • 1970-01-01
  • 2013-01-19
  • 2021-06-09
  • 2013-02-01
相关资源
最近更新 更多