AngularJS使用ng-upload上传图片

33

我正在尝试使用ng-upload在AngularJS中上传文件,但是遇到了问题。我的HTML代码如下:

<div class="create-article" ng-controller="PostCreateCtrl">
        <form ng-upload method="post" enctype="multipart/form-data" action="/write" >
            <fieldset>
                <label>Category</label>
                <select name="category_id" class="">
                    <option value="0">Select A Category</option>
                    <?php foreach($categories as $category): ?>
                        <option value="<?= $category -> category_id; ?>"><?= $category -> category_name; ?></option>
                    <?php endforeach; ?>
                </select>

                <label>Title</label>
                <input type="text" class="title span5" name="post_title"
                       placeholder="A catchy title here..."
                       value="<?= $post -> post_title; ?>" />

                <label>Attach Image</label>
                <input type="file" name="post_image" />

                 <a href='javascript:void(0)'  class="upload-submit: uploadPostImage(contents, completed)" >Crop Image</a>

                <label>Body</label>
                <div id="container">
                <textarea id="mytextarea" wrap="off" name="post_content" class="span7" placeholder="Content..."><?= $post -> post_content; ?></textarea>
                </div>
                <div style='clear:both;'></div>
                <label>Preview</label>
                <div id='textarea-preview'></div>

            </fieldset>
            <div class="span7" style="margin: 0;">
                <input type="submit" class="btn btn-success" value="Create Post" />
            <input type="submit" class="btn btn-warning pull-right draft" value="Save as Draft" />
            </div>

        </form>
    </div>

我的js控制器看起来像这样:

ClabborApp.controller("PostCreateCtrl", ['$scope', 'PostModel',
function($scope, PostModel) {

    $scope.uploadPostImage = function(contents, completed) {
        console.log(completed);
        alert(contents);
    }

}]);

我面临的问题是,在裁剪图像被点击并执行uploadPostImage时,它会上传整个表格。这不是期望的行为,但我可以让它工作。在JavaScript中,uploadPostImage函数的“contents”参数总是未定义,即使“completed”参数返回为true。

目标是仅上传要裁剪的图像。在此过程中我做错了什么?


1
访问此处以获取通过Angular进行简单图像上传的教程。它真的帮了我 https://www.tutorialspoint.com/angularjs/angularjs_upload_file.htm - Black Mamba
请注意,此问题涉及到 ng-upload 库,而不是 ng-file-upload 库。 - georgeawg
4个回答

63

关于在Angular中上传文件的文档非常少。很多解决方案需要自定义指令或其他依赖项(首先是jquery...只是为了上传一个文件...)。经过多次尝试,我发现只使用AngularJS(测试版本为1.0.6)就可以实现此功能。

html

<input type="file" name="file" onchange="angular.element(this).scope().uploadFile(this.files)"/>

AngularJS(1.0.6)不支持在“input-file”标签上使用ng-model,因此您必须以“本地方式”完成此操作,从用户传递所有(最终)所选文件。

控制器

$scope.uploadFile = function(files) {
    var fd = new FormData();
    //Take the first selected file
    fd.append("file", files[0]);

    $http.post(uploadUrl, fd, {
        withCredentials: true,
        headers: {'Content-Type': undefined },
        transformRequest: angular.identity
    }).success( ...all right!... ).error( ..damn!... );

};

有趣的部分是未定义的内容类型和transformRequest: angular.identity,它们使得$http能够选择正确的“内容类型”并在处理多部分数据时管理所需的边界。


2
你在使用这里发布的代码吗?关于发送JSON数据,其实我还不知道: p最好在此主题下发布一个新答案。 - Fabio Bonfante
我已经很久很久没有开发 PHP 了,但是无论如何,这个操作的效果就是使用一个名为“file”的文件构建表单,然后通过 POST 提交到“uploadUrl”。 - Fabio Bonfante
@StenMuchow 很遗憾,“file”似乎还不支持与ng-change绑定 https://github.com/angular/angular.js/issues/1375 - Fabio Bonfante
一切都运行良好,但我在服务器上看不到文件...服务器需要做额外的工作吗?建议使用 $_FILES 的 PHP 版本可以工作,但我需要一个 AngularJS 的解决方案! - alap
5
答案是针对AngularJS 1.0.6的。现在在Angular 1.2.26或1.3中是否有更好的解决方案?文档仍然没有给出更好的处理方法。 - floriank
显示剩余5条评论

19
你可以尝试使用ng-file-upload这个AngularJS插件(而不是ng-upload)。
它相当容易设置,并处理AngularJS的特定内容。它还支持进度、取消、拖放功能,并且跨浏览器兼容。
html
<!-- Note: MUST BE PLACED BEFORE angular.js-->
<script src="ng-file-upload-shim.min.js"></script> 
<script src="angular.min.js"></script>
<script src="ng-file-upload.min.js"></script> 

<div ng-controller="MyCtrl">
  <input type="file" ngf-select="onFileSelect($files)" multiple>
</div>

JS:

//inject angular file upload directives and service.
angular.module('myApp', ['ngFileUpload']);

var MyCtrl = [ '$scope', '$upload', function($scope, $upload) {
  $scope.onFileSelect = function($files) {
    //$files: an array of files selected, each file has name, size, and type.
    for (var i = 0; i < $files.length; i++) {
      var file = $files[i];
      $scope.upload = $upload.upload({
        url: 'server/upload/url', //upload.php script, node.js route, or servlet url
        data: {myObj: $scope.myModelObj},
        file: file,
      }).progress(function(evt) {
        console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
      }).then(function(response) {
        var data = response.data;
        // file is uploaded successfully
        console.log(data);
      });
    }
  };
}];

1
在我的情况下,上述方法在php中运行良好,但是当我尝试在node.js中使用这些方法上传文件时遇到了一些问题。因此,不要使用$http({...,...,...}),而是使用普通的jquery ajax。
要选择文件,请使用以下内容:
<input type="file" name="file" onchange="angular.element(this).scope().uploadFile(this)"/>

并在控制器中

$scope.uploadFile = function(element) {   
var data = new FormData();
data.append('file', $(element)[0].files[0]);
jQuery.ajax({
      url: 'brand/upload',
      type:'post',
      data: data,
      contentType: false,
      processData: false,
      success: function(response) {
      console.log(response);
      },
      error: function(jqXHR, textStatus, errorMessage) {
      alert('Error uploading: ' + errorMessage);
      }
 });   
};

这个答案使用jQuery而不是ng-file-upload或AngularJS的$http服务。 - georgeawg
@Tek Raj Pant,你有什么想法吗?我该如何在上面的HTML部分设置默认图像。我想设置一个默认图像,这样我的保存按钮就可以安全地工作,而不需要调用onchange。 - Dhwanil Patel

0
        var app = angular.module('plunkr', [])
    app.controller('UploadController', function($scope, fileReader) {
        $scope.imageSrc = "";

        $scope.$on("fileProgress", function(e, progress) {
        $scope.progress = progress.loaded / progress.total;
        });
    });




    app.directive("ngFileSelect", function(fileReader, $timeout) {
        return {
        scope: {
            ngModel: '='
        },
        link: function($scope, el) {
            function getFile(file) {
            fileReader.readAsDataUrl(file, $scope)
                .then(function(result) {
                $timeout(function() {
                    $scope.ngModel = result;
                });
                });
            }

            el.bind("change", function(e) {
            var file = (e.srcElement || e.target).files[0];
            getFile(file);
            });
        }
        };
    });

    app.factory("fileReader", function($q, $log) {
    var onLoad = function(reader, deferred, scope) {
        return function() {
        scope.$apply(function() {
            deferred.resolve(reader.result);
        });
        };
    };

    var onError = function(reader, deferred, scope) {
        return function() {
        scope.$apply(function() {
            deferred.reject(reader.result);
        });
        };
    };

    var onProgress = function(reader, scope) {
        return function(event) {
        scope.$broadcast("fileProgress", {
            total: event.total,
            loaded: event.loaded
        });
        };
    };

    var getReader = function(deferred, scope) {
        var reader = new FileReader();
        reader.onload = onLoad(reader, deferred, scope);
        reader.onerror = onError(reader, deferred, scope);
        reader.onprogress = onProgress(reader, scope);
        return reader;
    };

    var readAsDataURL = function(file, scope) {
        var deferred = $q.defer();

        var reader = getReader(deferred, scope);
        reader.readAsDataURL(file);

        return deferred.promise;
    };

    return {
        readAsDataUrl: readAsDataURL
    };
    });



    *************** CSS ****************

    img{width:200px; height:200px;}

    ************** HTML ****************

    <div ng-app="app">
    <div ng-controller="UploadController ">
        <form>
        <input type="file" ng-file-select="onFileSelect($files)" ng-model="imageSrc">
                <input type="file" ng-file-select="onFileSelect($files)" ng-model="imageSrc2">
        <!--  <input type="file" ng-file-select="onFileSelect($files)" multiple> -->
        </form>

        <img ng-src="{{imageSrc}}" />
    <img ng-src="{{imageSrc2}}" />

    </div>
    </div>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接