翻译于 2015/02/24 14:54
1 人 顶 此译文
The goal of this article is already said in the title. It's very simple. Here, I will document very simplest way to upload file using AngularJs and ASP.NET MVC5.
There are so many libraries to do this in online. So, What difference I will make? If this question comes to your head very first, then cool! Let's have a look why you must be bothered about this.
My requirement is very simple. I have a Model. Please see bellow
public class TutorialModel { public string Title { get; set; } public string Description { get; set; } public HttpPostedFileBase Attachment { get; set; } }
如题所示,在这里我将展示一种使用Angular.js和ASP.NET MVC5 来实现上传文件非常简单的方法.
网上已经有很多库实现这个功能了.而我的方法会有什么特别之处呢?如果你已经意识到这个问题了,是非常酷的.思考一下为什么我们会被这个问题一直困扰呢?
我们的要求非常简单,我有一个模型,如下:
public class TutorialModel { public string Title { get; set; } public string Description { get; set; } public HttpPostedFileBase Attachment { get; set; } }
I want to bind this model from client side with angular and post it to the ASP.NET MVC5 controller.
The most of the libraries that I found in online work in following way
1. Upload file --> Save it --> Return the file url in response
2. Send another request with model and file url
The common problem of this way is: every time you change the file, it will upload the file to the server. Previous files will not be deleted. So I don't want do this and may be even not you also. I will show how we can do it in one request. Users are free to change anything as many times they wish. When they will click save, then the Model will be sent to the server.
To do this, I will use here HTML5 FormData. I have writen a separate angular module for this so that any one can use it their module. Let have a look in my akFileUploader module.
"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: 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]); }); }); } }; }]);
What this module does, I will give you a very brief description. It has one directive and one factory service.
akFileModel Directive: It is responsible for changing file and binding it to the modelSetter
akFileUploaderService: It basically creates a FormData objects and send it to the desired url using $http.
为了实现功能,这里我会用到HTML5的表单数据.我曾经为这个写过一个分布式的angular模块以便让每个人都可以使用.让我们来看看我的akFileUploader模块.
"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: 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]); }); }); } }; }]);
至于这个模块是什么,我会给你一个简短的解释,他有一个directive(指令)和一个Factory.
akFileModel的指令: 他能响应式的为modelSetter改变文件和隐藏文件.
akFileUploader的服务: 它主要是创建一个表单数据和通过$http发送所需的URL.
application.js
"use strict"; (function () { angular.module("application", ["ngRoute", "akFileUploader"]); })();
template
<form class="form-horizontal"> <h4>Tutorial</h4> <hr /> <div class="form-group"> <label for="title" class="col-md-2 control-label">Title</label> <div class="col-md-10"> <input type="text" data-ng-model="tutorial.title" name="title" class="form-control" /> </div> </div> <div class="form-group"> <label for="description" class="col-md-2 control-label">Description</label> <div class="col-md-10"> <textarea data-ng-model="tutorial.description" name="description" class="form-control"> </textarea> </div> </div> <div class="form-group"> <label for="attachment" class="col-md-2 control-label">Attachment</label> <div class="col-md-10"> <input type="file" name="attachment" class="form-control" data-ak-file-model="tutorial.attachment" /> </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="button" class="btn btn-primary" value="Save" data-ng-click="saveTutorial(tutorial)" /> </div> </div> </form>
service:
"use strict"; (function () { angular.module("application") .factory("entityService", ["akFileUploaderService", function (akFileUploaderService) { var saveTutorial = function (tutorial) { return akFileUploaderService.saveModel(tutorial, "/controllerName/actionName"); }; return { saveTutorial: saveTutorial }; }]); })();
controller(js):
"use strict"; (function () { angular.module("application") .controller("homeCtrl", ["$scope", "entityService", function ($scope, entityService) { $scope.saveTutorial = function (tutorial) { entityService.saveTutorial(tutorial) .then(function (data) { console.log(data); }); }; }]); })();
MVC Controller Action:
[HttpPost] public ActionResult SaveTutorial(TutorialModel tutorial) { return Json("Tutorial Saved",JsonRequestBehavior.AllowGet); }
So I am done. Start using it. Thanks
application.js
"use strict"; (function () { angular.module("application", ["ngRoute", "akFileUploader"]); })();
template
<form class="form-horizontal"> <h4>Tutorial</h4> <hr /> <div class="form-group"> <label for="title" class="col-md-2 control-label">Title</label> <div class="col-md-10"> <input type="text" data-ng-model="tutorial.title" name="title" class="form-control" /> </div> </div> <div class="form-group"> <label for="description" class="col-md-2 control-label">Description</label> <div class="col-md-10"> <textarea data-ng-model="tutorial.description" name="description" class="form-control"> </textarea> </div> </div> <div class="form-group"> <label for="attachment" class="col-md-2 control-label">Attachment</label> <div class="col-md-10"> <input type="file" name="attachment" class="form-control" data-ak-file-model="tutorial.attachment" /> </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="button" class="btn btn-primary" value="Save" data-ng-click="saveTutorial(tutorial)" /> </div> </div> </form>
service:
"use strict"; (function () { angular.module("application") .factory("entityService", ["akFileUploaderService", function (akFileUploaderService) { var saveTutorial = function (tutorial) { return akFileUploaderService.saveModel(tutorial, "/controllerName/actionName"); }; return { saveTutorial: saveTutorial }; }]); })();
controller(js):
"use strict"; (function () { angular.module("application") .controller("homeCtrl", ["$scope", "entityService", function ($scope, entityService) { $scope.saveTutorial = function (tutorial) { entityService.saveTutorial(tutorial) .then(function (data) { console.log(data); }); }; }]); })();
MVC Controller Action:
[HttpPost] public ActionResult SaveTutorial(TutorialModel tutorial) { return Json("Tutorial Saved",JsonRequestBehavior.AllowGet); }
这里我就介绍完了,以上,谢谢