【问题标题】:Angular File Upload directive not updating controller modelAngular File Upload 指令不更新控制器模型
【发布时间】:2014-11-24 05:44:24
【问题描述】:

我正在尝试关注此[tutorial],但无法正常工作。

我的 Angular 控制器正在为在我的指令中创建的模型记录 undefined。 这是一个[JSFiddle] 它的工作创建了我的教程作者。

问题是视图可以找到$scope.myFile,但控制器没有($scope.myFileundefined)。

视图显示{{ myFile.name }}(例如my-image.jpg)。 myFile 变量是一个包含所选文件数据的 JS 对象。这工作正常。该指令似乎正在为模型分配所选文件的值(从而在视图中正确显示它)。

<input file-model="myFile" type="file"/ >
<div class="label label-info">
  {{ myFile.name }}
</div>
<button ng-click="uploadDocs()">Click</button>

这是我从[tutorial] 得到的指令。

由于输入类型file 不能使用ng-model,该指令将模型设置为与file 输入相关联,并在每次文件触发change 事件时分配给它。

directive('fileModel', [
  '$parse',
    function ($parse) {
      return {
        restrict: 'A',
        link: function(scope, element, attrs) {
          var model = $parse(attrs.fileModel);
          var modelSetter = model.assign;

          element.bind('change', function(){
            scope.$apply(function(){
              if (element[0].files.length > 1) {
                modelSetter(scope, element[0].files);
              }
              else {
                modelSetter(scope, element[0].files[0]);
              }
            });
          });
        }
      };
    }
  ]).

在控制器中我只记录$scope.myFile。这是从上面 HTML 中的按钮调用的。 理想情况下,我会在这里将文件上传到服务器,但我不能,因为 $scope.myFile 未定义。

$scope.uploadDocs = function() {
  var file = $scope.myFile;
  console.log($scope.myFile);
};

谁能告诉我为什么视图会收到$scope.myFile,但控制器会记录undefined$scope.myFile

【问题讨论】:

  • 尝试将我的文件初始化为控制器的第一行:$scope.myFile = {}; 这主要是点问题
  • 我已经对您提供的代码进行了 plunkr,它工作正常:plnkr.co/edit/o9D2Q6Tzkesm5MTyqXFE?p=preview
  • 今天遇到了这个问题。将'myFile'传递给uploadDocs()这样的uploadDocs(myfile)函数,似乎做到了
  • @akinwale 的解决方案对我有用
  • 我对同一个 jsfiddle 有完全相同的问题,由于某种原因,它在我的代码中不起作用,但在小提琴中可以正常工作。 @Akinwale 的解决方案对我有用,但是在挣扎了三个小时之后,我非常想知道为什么它不起作用!这种解决方法很好,但理解问题对我来说很重要。

标签: javascript angularjs angularjs-directive angularjs-scope


【解决方案1】:

我在尝试从控制器访问指令的变量时遇到了同样的问题。在我的情况下,我可以让控制器使用myFile,但我必须在指令中将它分配给scope.$parent.$parent.myFile。我不想为了访问变量而对祖先的深度进行硬编码,所以我最终使用服务在指令和控制器之间共享变量:

.factory('fileService', function() {
    var files = [];
    return files;
})

我的指令代码更改为使用服务而不是教程中使用的attrs.fileModel

.directive('fileModel', ['$parse', 'fileService', function ($parse, fileService) {
    return {
        restrict: 'A',
        link: function(scope, element) {
            element.bind('change', function(){
                scope.$apply(function(){
                    if (element[0].files != undefined) {
                        fileService.push(element[0].files[0]);
                        console.log('directive applying with file');
                    }
                });
            });
        }
    };
}])

然后,将 fileService 注入控制器后,我可以直接从 fileService 访问文件:

$scope.uploadDocs = function() {
    console.log(fileService);
};

【讨论】:

  • 使用 ng-annotate 时出现同样的问题,modelSetter 对我不起作用,除非我使用服务共享变量。
  • 我仍然非常想知道为什么 Q 中的教程可以正常工作(对我来说也是如此)但在我自己的代码中实现却没有 - 我得到与 $ 的 OP 相同的错误scope.myFile 未定义。尽管如此,这个解决方案仍然有效并且很容易理解,所以格伦赢得了赏金。
【解决方案2】:

这个问题出现在几个 Angular 版本中,其中文件对象无法设置范围变量。作为解决方法,将字段传递给控制器​​,使用此文件对象上传(不是从范围)

HTML 表单

<form>
    <div class="form-group">
                    <label for="myFileField">Select a file: </label> 
                    <input type="file" file-model="myFile" /> <label>File Name:</label> 
                    <input type="text" ng-model="filename"></input>
                </div>
                <button ng-click="uploadFile(myFile)" class="btn btn-primary">Upload File</button>
            </form>

控制器

 $scope.uploadFile = function (file1) {
            var file = $scope.myFile;  // this is undefined 
            console.log("My file =" +file1); // you get this 
            // Make http call to upload the file or make service call         
 }

希望这能解决问题

【讨论】:

    【解决方案3】:

    我看过该教程,但选择使用这个库,使文件上传无缝: ng-file-upload

    【讨论】:

      【解决方案4】:

      尝试以下解决方案: HTML 代码:

      <div class="btn-header">
          <label for="attachment" class="control-label">Attachment</label>
          <div class="has-feedback">
              <input type="file" id="fileUpload" name="attachment" ng-disabled="BRPTab.BRPTelePhonyandTestScipt.Checked"
                     class="form-control" data-ak-file-model="BRPTab.tutorial.attachment" />
              <span class="form-control-feedback" aria-hidden="true"></span>
              <div class="help-block with-errors"></div>
          </div>
      </div>
      

      服务代码:

          AppService.factory("entityService", ["akFileUploaderService", function(akFileUploaderService) {
          var saveTutorial = function(tutorial, url) {
      
              return akFileUploaderService.saveModel(tutorial, url);
          };
          return {
              saveTutorial: saveTutorial
          };
      }]);
      
      (function() {
          "use strict"
          angular.module("akFileUploader", [])
              .factory("akFileUploaderService", ["$q", "$http",
                  function($q, $http) {
                      var getModelAsFormData = function(data) {
                          var dataAsFormData = new FormData();
                          angular.forEach(data, function(value, key) {
                              dataAsFormData.append(key, value);
                          });
      
                          return dataAsFormData;
                      };
      
                      var saveModel = function(data, url) {
      
      
                          var deferred = $q.defer();
                          $http({
                              url: url,
                              method: "POST",
                              //data:
                              //    {
                              //        tutorial: getModelAsFormData(data),
                              //        Object: Obj
                              //    },
                              //params: Indata,
                              data: getModelAsFormData(data),
                              transformRequest: angular.identity,
                              headers: {
                                  'Content-Type': undefined
                              }
                          }).success(function(result) {
      
                              deferred.resolve(result);
                          }).error(function(result, status) {
                              deferred.reject(status);
                          });
                          return deferred.promise;
                      };
      
                      return {
                          saveModel: saveModel
                      }
      
                  }
              ])
              .directive("akFileModel", ["$parse",
                  function($parse) {
                      return {
                          restrict: "A",
                          link: function(scope, element, attrs) {
                              var model = $parse(attrs.akFileModel);
                              var modelSetter = model.assign;
                              element.bind("change", function() {
                                  scope.$apply(function() {
                                      modelSetter(scope, element[0].files[0]);
                                  });
                              });
                          }
                      };
                  }
              ]);
      })(window, document);
      

      如果你们遇到任何问题,请告诉我。

      【讨论】:

        【解决方案5】:

        试试这个代码

                        <html>
        
                       <head>
                          <script src = "https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
                       </head>
        
                       <body ng-app = "myApp">
        
                          <div ng-controller = "myCtrl">
                             <input type = "file" file-model = "myFile"/>
                             <button ng-click = "uploadFile()">upload me</button>
                          </div>
        
                          <script>
                             var myApp = angular.module('myApp', []);
        
                             myApp.directive('fileModel', ['$parse', function ($parse) {
                                return {
                                   restrict: 'A',
                                   link: function(scope, element, attrs) {
                                      var model = $parse(attrs.fileModel);
                                      var modelSetter = model.assign;
        
                                      element.bind('change', function(){
                                         scope.$apply(function(){
                                            modelSetter(scope, element[0].files[0]);
                                         });
                                      });
                                   }
                                };
                             }]);
        
                             myApp.service('fileUpload', ['$http', function ($http) {
                                this.uploadFileToUrl = function(file, uploadUrl){
                                   var fd = new FormData();
                                   fd.append('file', file);
        
                                   $http.post(uploadUrl, fd, {
                                      transformRequest: angular.identity,
                                      headers: {'Content-Type': undefined}
                                   })
        
                                   .success(function(){
                                   })
        
                                   .error(function(){
                                   });
                                }
                             }]);
        
                             myApp.controller('myCtrl', ['$scope', 'fileUpload', function($scope, fileUpload){
                                $scope.uploadFile = function(){
                                   var file = $scope.myFile;
        
                                   console.log('file is ' );
                                   console.dir(file);
        
                                   var uploadUrl = "/fileUpload";
                                   fileUpload.uploadFileToUrl(file, uploadUrl);
                                };
                             }]);
        
                          </script>
        
                       </body>
                    </html>
        

        【讨论】:

          猜你喜欢
          • 2016-07-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-03-03
          • 2018-03-28
          • 1970-01-01
          • 2016-09-04
          • 1970-01-01
          相关资源
          最近更新 更多