Reputation: 1460
My example works only with one file. I need an array of files. I use angularJS 1.7 and asp.net-core 2.0
HTML
<div class="post">
<form>
<textarea ng-model="Headline" name="Headline" rows="2" cols="63" class="form-control"></textarea>
<textarea ng-model="BodyText" name="BodyText" rows="4" cols="63" class="form-control"></textarea>
<input type = "file" file-model = "myFile" multiple/>
<input id="Submit" class="btn btn-default" ng-click="createPost()" type="submit" value="Пост" />
</form>
</div>
Method creatPost in AgularJs controller
$scope.createPost = function () {
var model = {
Headline: $scope.Headline,
BodyText: $scope.BodyText,
ImgPost: $scope.myFile
}
$http({
method: 'POST',
url: '/api/Blog/create-post/',
headers: {
'Content-Type': undefined
},
data: model,
transformRequest: function (data, headersGetter) {
var formData = new FormData();
angular.forEach(data, function (value, key) {
formData.append(key, value);
});
return formData;
}
})
.then(function onSuccess(response) {
if (response.data = "Ok") {
$window.location.reload();
}
})
.catch(function onError(response) {
console.log("Error")
});
}
Model in C#
[ScaffoldColumn(false)]
public int Id { get; set; }
[ScaffoldColumn(false)]
public string User { get; set; }
[Required(ErrorMessage = "")]
[StringLength(100, MinimumLength = 1, ErrorMessage = "")]
public string Headline { get; set; }
[Required(ErrorMessage = "")]
[StringLength(1000, MinimumLength = 1, ErrorMessage = "")]
public string BodyText { get; set; }
[ScaffoldColumn(false)]
public DateTime? Date_Time { get; set; }
public IFormFile ImgPost { get; set; }
And a method signature
[HttpPost]
[Route("create-post")]
public async Task<object> PostSaveOnFile(PostViewModel model)
{
How I need to change my model in # public IFormFile ImgPost { get; set; } And make changes on my angularJS controller and I shoud be able to sent an array of files. Thanks.
As I understood the problem in my derective of fileReader
(function (angular) {
angular.module('app').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]);
});
});
}
};
}]);
})(window.angular);
If I will change in my C# model to IList or IEnumerable it will be only the first file. I did nor understand how to change my derective to array
Upvotes: 1
Views: 952
Reputation: 9642
At first you need to update fileModel
directive to set an array of files instead of single file. You can use this answer but the resulting array will have FileList
type and I suggest you to convert it to Array
because it will be more flexible in conjunction with other changes in code
app.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, Array.from(element[0].files));
});
});
}
};
}]);
In order to let ASP.NET Core properly bind an Array
(or List
) you need to add all array values with the same key to FormData
. For instance, if you have
public List<string> Strings { get; set; }
you will need to append the values with Strings
key
formData.append("Strings", "value1");
formData.append("Strings", "value2");
formData.append("Strings", "value3");
So you need to update transformRequest
function to properly add an array of files to FormData
function (data, headersGetter) {
var formData = new FormData();
angular.forEach(data, function (value, key) {
//you could check if value is FileList
//but your model can hold array of primitive values like ["val1", "val2", "val3"]
//this single check for Array covers all cases
//and you don't need to have different check for FileList
if (value instanceof Array) {
for (var i = 0; i < value.length; i++) {
formData.append(key, value[i]);
}
return;
}
formData.append(key, value);
});
return formData;
}
Upvotes: 2
Reputation: 48968
I did nor understand how to change my derective to array
app.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() {
̶m̶o̶d̶e̶l̶S̶e̶t̶t̶e̶r̶(̶s̶c̶o̶p̶e̶,̶ ̶e̶l̶e̶m̶e̶n̶t̶[̶0̶]̶.̶f̶i̶l̶e̶s̶[̶0̶]̶)̶;̶
modelSetter(scope, element[0].files);
});
});
}
};
}]);
Change the modelSetter
call to return an array.
Upvotes: 1