【问题标题】:Directive / controller scope undefined when injecting directive in controller在控制器中注入指令时未定义指令/控制器范围
【发布时间】:2023-03-13 08:11:02
【问题描述】:

我有这个 html

<input type="file" file-input="files" multiple />
<button ng-click="upload()" type="button">Upload</button>
<li ng-repeat="file in files">{{file.name}}</li>

这个指令:

.directive('fileInput', ['$parse', function($parse){
    return {
        restrict: 'A',
        link: function(scope, elm, attrs){
            //console.log("directives scope: ")

            elm.bind('change', function(){

                $parse(attrs.fileInput)
                .assign(scope,elm[0].files)
                scope.$apply()
                //console.log(scope);
            })
        }
    }
}]);

在我的控制器中我有这个功能:

$scope.upload=function(){
    console.log($scope.files)
    var fd = new FormData() // put these 3 lines in a service
    angular.forEach($scope.files, function(file){
      fd.append('file', file)
    })
    $http.post('/api/directory/upload-file-test', fd,
    {
      transformRequest: angular.identity, // returns first argument it is passed
      headers:{'Content-Type': undefined} //multipart/form-data
    })
    .success(function(d){
      console.log(d)
      console.log("works?")
    })
  }

如果我像往常一样直接将 HTML 放入 html 文件中,效果很好,但是...

我需要注入它,当我这样做时,指令范围和控制器范围不一样..所以我在指令中添加到 scope.files 的文件只是控制器函数内部的“未定义” ,所以我的文件上传中断...

更确切地说...

如果我这样做:

<tr ng-repeat="prop in tab.properties">
  <td>{{prop.name}}</td>
  <td compile ng-bind-html="prop.data_type.html | unsafe"></td>
  <td>{{prop.description}}</td>
</tr>

ng-bind-html 引号 (prop.data_type.html) 中的内容就等于这个:

<input type="file" file-input="files" multiple />
<button ng-click="upload()" type="button">Upload</button>
<li ng-repeat="file in files">{{file.name}}</li>

它不起作用。作用域不同。

我的编译指令如下所示:

.directive('compile',function($compile, $timeout){
    return{
        restrict:'A',
        link: function(scope,elem,attrs){
            $timeout(function(){                
                $compile(elem.contents())(scope);    
            });
        }        
    };
})

最后一个相关的代码是不安全过滤器,它是这样的:

.filter('unsafe', function($sce) {
    return function(val) {
        return $sce.trustAsHtml(val);
    };
})

有谁知道为什么我的控制器和指令范围内的“上传”功能不能保持同步并引用相同的范围ng-bind-html?有什么办法解决这个问题,还是我必须避免使用指令来完成这项工作?

我首先尝试了 Angular 1.3.0 rc4,现在升级到最新版本 v. 1.3.5 后它仍然是一样的。

【问题讨论】:

  • 为什么不能使用ng-include 而不是ng-bind-html + 自定义compile 指令?
  • 我可以理解您的问题,因为我没有向您展示 ng-bind-html 行实际上是在 ng-repeat“循环”中(更新了代码片段),您必须想象该元素包含“数据类型”的 html 标记。它们都是不同的,所以开始制作模板并包含这些不是一个有效的解决方案。
  • 如果您尝试将三行内容(您尝试通过ng-bind-html 导入)直接放在ng-repeat 中,您将获得相同的效果。换句话说,这不是 compile 指令 - 它是 ng-repeat 为每次迭代创建子范围,并且您的 files 被分配给该子范围。
  • 如果你打算在页面中多次使用它们,你应该考虑为你的指令创建一个 IsolateScope。
  • 我不打算在每页中多次使用它。每页只有 1 个文件上传器,但感谢您尝试为我指明正确的方向 - 非常感谢。如果我找到解决方案,我会在这里发布。 :)

标签: angularjs controller scope directive inject


【解决方案1】:

我能够解决这个问题,这是简单的解决方案:

(旧代码):

<input type="file" file-input="files" multiple />
<button ng-click="upload()" type="button">Upload</button>
<li ng-repeat="file in files">{{file.name}}</li>

替换为:

<input type="file" file-input="test.files" multiple />
<button ng-click="upload()" type="button">Upload</button>
<li ng-repeat="file in test.files">{{file.name}}</li>

还有这段旧代码:

.directive('fileInput', ['$parse', function($parse){
    return {
        restrict: 'A',
        link: function(scope, elm, attrs){
            //console.log("directives scope: ")

            elm.bind('change', function(){

                $parse(attrs.fileInput)
                .assign(scope,elm[0].files)
                scope.$apply()
                //console.log(scope);
            })
        }
    }
}]);

应该替换为:

.directive('fileInput', ['$parse', function($parse){
    return {
        restrict: 'A',
        link: function(scope, elm, attrs){
            if(typeof(scope.test) == undefined){
              scope.test = { "files": []}
            }
            if(typeof(scope.test.files) !== undefined){
              scope.test["files"] =[]
            }
            elm.bind('change', function(){

                $parse(attrs.fileInput)
                .assign(scope,elm[0].files)
                scope.$apply()
            })
        }
    }
}]);

与控制器功能相同(旧代码优先):

$scope.upload=function(){
    console.log($scope.files)
    var fd = new FormData() // put these 3 lines in a service
    angular.forEach($scope.files, function(file){
      fd.append('file', file)
    })
    $http.post('/api/directory/upload-file-test', fd,
    {
      transformRequest: angular.identity, // returns first argument it is passed
      headers:{'Content-Type': undefined} //multipart/form-data
    })
    .success(function(d){
      console.log(d)
      console.log("works?")
    })
  }

解决方案:

  $scope.test = {files:undefined}

  $scope.upload=function(){
    console.log($scope.test.files)
    var fd = new FormData() // put these 3 lines in a service
    angular.forEach($scope.test.files, function(file){
      fd.append('file', file)
    })
    $http.post('/api/directory/upload-file-test', fd,
    {
      transformRequest: angular.identity, // returns first argument it is passed
      headers:{'Content-Type': undefined} //multipart/form-data
    })
    .success(function(d){
      console.log(d)
      console.log("works?")
    })
  }

如果您需要更多解释,智者 Josh David Miller 可以在这里找到。这是让我意识到如何解决这个问题的评论:https://stackoverflow.com/a/15645354/3973406

基本上它与隔离范围无关,但因为我们违反了规则,而 Angular 对此很讨厌!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-26
    • 1970-01-01
    • 1970-01-01
    • 2015-04-30
    • 2016-03-28
    • 1970-01-01
    相关资源
    最近更新 更多