AngularJS:使用$ resource上传文件(解决方案)

AngularJS:使用$ resource上传文件(解决方案),第1张

AngularJS:使用$ resource上传文件(解决方案)

我进行了无数次搜索,尽管可能会错过它,但找不到该问题的解决方案:使用$ resource *** 作上传文件。

让我们举个例子:RESTful服务允许我们通过向

/images/
端点发出请求来访问图像。每个
Image
都有标题,描述和指向图像文件的路径。使用RESTful服务,我们可以获得所有这些(
GET/images/
),单个(
GET /images/1
)或添加一个(
POST/images
)。Angular允许我们使用$resource服务轻松完成此任务,但不允许开箱即用地进行文件上传(这是第三项 *** 作所必需的)(而且他们似乎并没有计划随时支持它)很快)。如果无法处理文件上传,那么我们将如何使用非常方便的$resource服务呢?事实证明这很容易!

我们将使用数据绑定,因为它是AngularJS的出色功能之一。我们有以下HTML表单:

<form  name="form" novalidate ng-submit="submit()">    <div >        <input  ng-model="newImage.title" placeholder="Title" required>    </div>    <div >        <input  ng-model="newImage.description" placeholder="Description">    </div>    <div >        <input type="file" files-model="newImage.image" required >    </div>    <div >        <button  type="submit" ng-disabled="form.$invalid">Save</button>    </div></form>

如您所见,有两个文本

input
字段分别绑定到单个对象属性,我称之为
newImage
。该文件也
input
被绑定到
newImage
对象的属性,但是这次我使用了直接从这里获取的自定义指令。使用此伪指令可以使每次文件内容
input
更改时,都将FileList对象放置在binded属性中,而不是a
fakepath
(这是Angular的标准行为)。

我们的控制器代码如下:

angular.module('clientApp').controller('MainCtrl', function ($scope, $resource) {    var Image = $resource('http://localhost:3000/images/:id', {id: "@_id"});    Image.get(function(result) {        if (result.status != 'OK') throw result.status;        $scope.images = result.data;    })    $scope.newImage = {};    $scope.submit = function() {        Image.save($scope.newImage, function(result) { if (result.status != 'OK')     throw result.status; $scope.images.push(result.data);        });    }});

(在这种情况下,我正在本地计算机上的端口3000上运行NodeJS服务器,并且响应是一个包含一个

status
字段和一个可选
data
字段的json对象)。

为了使文件上传正常工作,我们只需要正确配置$http服务,例如在app对象上的.config调用中即可。具体来说,我们需要将每个发布请求的数据转换为FormData对象,以便以正确的格式将其发送到服务器:

angular.module('clientApp', ['ngcookies','ngResource','ngSanitize','ngRoute']).config(function ($httpProvider) {  $httpProvider.defaults.transformRequest = function(data) {    if (data === undefined)      return data;    var fd = new FormData();    angular.forEach(data, function(value, key) {      if (value instanceof FileList) {        if (value.length == 1) {          fd.append(key, value[0]);        } else {          angular.forEach(value, function(file, index) { fd.append(key + '_' + index, file);          });        }      } else {        fd.append(key, value);      }    });    return fd;  }  $httpProvider.defaults.headers.post['Content-Type'] = undefined;});

Content-Type
首部设置为
undefined
,因为手动设置它来
multipart/form-data
将未设定边界值,并且服务器将不能正确解析该请求。

而已。现在你可以使用

$resource
save()
含有标准的数据字段和文件的对象。

警告 这有一些限制:

  1. 在较旧的浏览器上不起作用。对不起:(
  2. 如果您的模型具有“嵌入式”文档,例如

{ title: "A title", attributes: { fancy: true, colored: false, nsfw: true },image: null }

那么您需要相应地重构transformRequest函数。 例如,您可以

JSON.stringify
嵌套对象,前提是您可以在另一端解析它们

  1. 英语不是我的主要语言,所以如果我的解释不清楚,请告诉我,我将尝试重新措辞:)

  2. 这只是一个例子。您可以根据您的应用程序需要做什么来扩展它。

我希望这会有所帮助,加油!

编辑:

正如@david指出的那样,一种侵入性较小的解决方案是仅针对

$resource
实际需要此行为的用户定义此行为,而不转换AngularJS提出的每个请求。您可以这样创建自己的代码
$resource

$resource('http://localhost:3000/images/:id', {id: "@_id"}, {     save: {         method: 'POST',         transformRequest: '<THE TRANSFORMATION METHOD DEFINED ABOVE>',         headers: '<SEE BELOW>'     } });

至于标题,您应该创建一个满足您要求的标题。您唯一需要指定的是将

'Content-Type'
属性设置为
undefined



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/4894740.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-12
下一篇 2022-11-12

发表评论

登录后才能评论

评论列表(0条)

保存