AngularJS Upload and Post Multiple Files - angularjs

So ultimately, what I'm doing is trying to upload and post multiple files to a Django backend using AngularJS. I can post a single file, but it seems like when a FileList object is put in the $http.post data field, the backend no longer detects any files in the POST request.
Here's what the html looks like:
<form enctype="multipart/form-data" action="upload" method="POST">
<div class="form-group">
<span class="btn btn-info btn-file">
<i class="glyphicon glyphicon-file"></i> Browse
<input class="btn btn-lg btn-info" name="uploadedfile" type="file" accept=".eossa" onchange="angular.element(this).scope().filesUploaded(this.files)" multiple><br/>
</span>
<button type="button" class="btn btn-success" ng-click="uploadFiles()" ng-class="{'disabled':!model.files.length}">
<i class="glyphicon glyphicon-download-alt"></i> Submit
</button>
</div>
<pre ng-repeat="file in model.files" ng-show="file.name">{{file.name}} ({{file.size/1000}} KB) {{file.lastModifiedDate}} </pre>
</form>
And here's the relevant JavaScript:
$scope.filesUploaded = function(files) {
if(files.length < 1) return;
$scope.model.files = files;
$scope.$apply();
};
$scope.uploadFiles = function(){
var fd = new FormData();
fd.append("file", $scope.model.files);
Services.uploadFiles(fd)}
Here's my uploadFiles service:
uploadFiles: function(form){
return $http.post("/api/file-upload/", form, {withCredentials: true, headers: {'Content-Type': undefined }, transformRequest: angular.identity})
},
The backend does not see anything in the request.FILES in this case; however, if instead of appending $scope.model.files, I append $scope.model.file[0], I do see a file in the request on the backend. In which case, the uploadFiles function looks like this:
$scope.uploadFiles = function(){
var fd = new FormData();
fd.append("file", $scope.model.files[0]);
Services.uploadFiles(fd)
}
So why can't one append a FileList to a Form? How can you POST a FileList?
Thanks

First create a directive as pointed out here
.directive('filesModel', function () {
return {
restrict: 'A',
controller: function ($parse, $element, $attrs, $scope) {
var exp = $parse($attrs.filesModel);
$element.on('change', function () {
exp.assign($scope, this.files);
$scope.$apply();
});
}
};
});
And for the transform function, check this out.
You can use a factory like:
.factory('File', function () {
return {
// Define a function to transform form data
transformRequest: function (data, headersGetter) {
var fd = data ? new FormData() : null;
if (data) {
angular.forEach(data, function (value, key) {
// Is it a file?
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);
});
}
}
// Is it an object?
else if (typeof value === 'object') {
fd.append(key, JSON.stringify(value));
} else {
fd.append(key, value);
}
});
}
return fd;
}
};
})
Then for the service:
uploadFiles: function(form){
return $http.post("/api/file-upload/", form, {withCredentials: true, headers: {'Content-Type': undefined }, transformRequest: File.transformRequest})
}
Finally the html:
<input type="file" files-model="<model>"/>
Or this for multiple files
<input type="file" files-model="<model>" multiple/>

I've never tried the method above and this may be a cop out but I thought I would turn you on to some libraries.
I would checkout these two awesome AngularJS file upload Repos. I personally use this one.
Both support easy setup multiple file upload.
ng-file-upload
Here's another.
angular-file-upload
Why put in hours of work when dozens of folks have contributed and done it for you?

Related

Cannot send excel file to server, asp.net doesn't see any files.IFormFile is null in API

on client-side:
Uploading excel file.
<div>
<form>
<div>
<label for="myFileField">Select a file: </label>
<input type="file" demo-file-model="myFile" class="form-control" id="myFileField" />
</div>
<button ng-click="uploadFile()" class="btn btn-primary">Upload File</button>
</form>
</div>
angular controller:
$scope.uploadFile = function () {
var file = $scope.myFile;
Service.fileUploadAll(file,
function (response) {
});
fileUploadAll(file) {
var fileFormData = new FormData();
fileFormData.append('file', file);
return this.promiser.post('/api/fileUpload', fileFormData);
}
[HttpPost("fileUpload")]
public IActionResult fileUploadAll(IFormFile file)
{
// Do some
}
I'm working on Asp.NET Core .
Please help me to resolve this issue.
You need add header and set content type here like this :
fileUploadAll(file) {
var fileFormData = new FormData();
fileFormData.append('file', file);
return this.promiser.post('/api/fileUpload', fileFormData, {transformRequest: angular.identity, headers: {'Content-Type': undefined}});
Let me know please.

How to disable buttons until http request is processed/loaded in AngularJS?

I want to write a directive that keeps a button and page disabled for the duration of the http request.
If I update or submit a form, the button will disable until the http
response is complete.
When a page is loading, it will disable until the entire data is
loaded from the server.
After 10 seconds, the button will be active and the user can click
multiple times.
app.js
<script>
var angModule = angular.module("myApp", []);
angModule.controller("myCtrl", function ($scope, $timeout) {
$scope.isSaving = undefined;
$scope.btnVal = 'Yes';
$scope.save = function()
{
$scope.isSaving = true;
$timeout( function()
{
$scope.isSaving = false;
}, 1000);
};
});
</script>
index.html
<div ng-app="myApp">
<ng-form ng-controller="myCtrl">
Saving: {{isSaving}}
<button ng-click="save()" ng-disabled="isSaving">
<span ng-hide="isSaving">Save</span>
<span ng-show="isSaving">Loading...</span><i class="fa fa-spinner fa-spin" ng-show="isSaving"></i>
</button>
</ng-form>
</div>
I am new to AngularJS, please help me write a directive for this.
here a basic example :
<button ng-click="save()" loading="Loading..." notloading="save" disableonrequest>
myApp.directive("disableonrequest", function($http) {
return function(scope, element, attrs) {
scope.$watch(function() {
return $http.pendingRequests.length > 0;
}, function(request) {
if (!request) {
element.html("<span >"+attrs.notloading+"</span>");
} else {
element.html("<span >"+attrs.loading+"</span><i class='fa fa-spinner fa-spin'></i>");
}
});
}
});
A WORKING EXAMPLE
Depending on your needs, you may not necessarily need a custom directive for this simple task.
You can simply set the $scope.isSaving property inside the callback for $http.
For example
$http({
url: 'http://path/to/the/api/',
method: 'GET',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
}
})
.success(function(data, status){
$scope.isSaving = false;
})
.error(....);

Uploading files in Ionic application using Web API

My issue is as below.
I have given WEB API where I have to add boards picture.
What I have to DO?
User should able to select Image from Phone
User can add Name of board
When user click on submit, entered board name and board image should post using Web API with method of PUT. Here below is WEB API Details
WEB API Details
Header
URL: https://example.com
Content-Type: | Content Type |
Method: PUT
Data
board_id: 321
board_title: | Title |
board_background: | File |
I have used cordovaImagePicker plugin to select image and then I get stuck to uploading it to Server.
I can use cordova file transfer plugin but I think that will not help me in this case as there is no specified place to store image. All the file management done by WEB API, we have to just post file with Data.
After trying a lot solution I have come with below answer.
Board.html
<ion-view>
<ion-nav-bar class="bar">
<ion-nav-title>
<h1 class="title">
Create Board
</h1>
</ion-nav-title>
</ion-nav-bar>
<form name="boardForm" ng-submit="addBoard(data)">
<ion-content padding="false" scroll="true" has-bouncing="false">
<div id="form">
<div style="text-align: center; padding-top: 2%; padding-bottom: 2%;">
<div id="image-preview">
<label for="image-upload" id="image-label"><img src="{{ImagePrefix}}/task_plus.png" alt=""/></label>
<input type="file" name="board_background" id="image-upload" file-model="data.board_background">
</div>
<p>Add Cover</p>
</div>
<ion-list>
<ion-item style="background-color: #F8F8F8;">
<label class="control-label" for="board_name">BOARD NAME</label>
</ion-item>
<ion-item ng-class="{true:'error'}[submitted && boardForm.board_title.$invalid]">
<input type="text" id="board_name" ng-model="data.board_title"
placeholder="Add a Name" name="board_title" required>
<p ng-show="submitted && boardForm.board_title.$error.required">
Please enter a board name
</p>
</ion-item>
</ion-list>
</div>
</ion-content>
<ion-footer-bar>
<button class="button button-block control-button bottomOfPage"
ng-click="submitted = true">
CREATE
</button>
</ion-footer-bar>
</form>
</ion-view>
directive
.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]);
});
});
}
};
}])
Controller
.controller('ManageBoardCtrl', function ($scope, $http, $ionicPopup, $state, BoardService) {
$scope.submitted = false;
$scope.data = {};
$scope.addBoard = function(formData) {
BoardService.CreateBoard(formData).then(function(response) {
if (response === "success") {
$ionicPopup.alert({
title: "Success",
template: "Board created successfully"
});
}
}, function (response) {
$ionicPopup.alert({
title: "Failed",
template: "Somethings wrong, Can not create boards at now."
});
});
}
})
Service
.service('BoardService', function ($q, $http) {
var getUrl = API_URL + "boards";
var createBoard = function (fData) {
var formData = new FormData();
formData.append("board_title", fData.board_title);
formData.append("board_background", fData.board_background);
return $q(function (resolve, reject) {
$http({
transformRequest: angular.identity,
method: 'POST',
url: getUrl,
headers: { 'Content-Type': undefined },
data: formData
}).success(function (response) {
if (response.success === true) {
resolve('success');
} else {
reject('fail');
}
}).error(function () {
reject('requesterror');
});
});
};
return {
CreateBoard: createBoard
};
})
After deploying application for android / iPhone file selection will handle the browsing Images based on the OS.
One simple thing I can suggest,
Use input["file"] tag to select the image. You will get the file object and a temporary url. with this url you can show the image in the form.
Then use formData to append the image and the other field.
e.g.
var fd = new FormData();
fd.append('board_background', $scope.image, $scope.image.name);
fd.append('board_id', 321);
fd.append('board_title', 'Dummy title');
var xhr = new XMLHttpRequest();
xhr.open('PUT', YOUR_URL, true);
xhr.onload(function(res){
// Write your callback here.
});
// Send the Data.
xhr.send(fd);
Hope it will help you and meet your requirements.
First of all to need to select the image from device.
vm.getImages = function () {
var options = {
quality: 70,
destinationType: Camera.DestinationType.DATA_URL,
sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
allowEdit: true,
correctOrientation:true,
encodingType: Camera.EncodingType.JPEG,
targetWidth: 300,
popoverOptions: CameraPopoverOptions,
saveToPhotoAlbum: true
};
navigator.camera.getPicture(onSuccess, onFail, options);
function onSuccess(imageURI) {
vm.image = "data:image/jpeg;base64," + imageURI;
vm.imageURI = imageURI;
}
function onFail(message) {
console.log('Failed because: ' + message);
}
};
You can change the source type for input if needed.
sourceType: Camera.PictureSourceType.CAMERA,
On success you get ImageURI either use it directly or convert it to base64 as mentioned below for uploading.
vm.image = "data:image/jpeg;base64," + imageURI;
After this you can use the FileTransfer plugin to upload file and track the progress at the same time.
cordovaFileTransfer.upload()
.then(function (result) {},
function (err) {},
function (progress) {});
Below link will definitely help you:
http://ionicmobile.blogspot.in/2015/10/jquery-file-upload.html
Make the appropriate changes if needed. Any help let me know...

Want to upload file locally with html and angularjs

I've html page which uploads the file. As of now, I want to store it locally. I'm using angularjs for this. I've gone through many solutions but didn't work. This is my html file:
<body>
<form action="go" method="post" enctype="multipart/form-data">
Select File:<input type="file" name="filename"/><br/>
<input ng-click="submit()" class="btn btn-md btn-primary"
type="submit" value="{{ 'UPLOAD' | translate }}" >
</input>
</form>
</body>
Please don't get confused with directives. They are from bootstrap.
I've done necessary changes in app.js. The uploadcontroller is getting access. The thing is I don't have any idea what to write in function so that the file will get stored locally. This is my controller:
newController.controller("UploadController", function($scope, $location, ezfb) {
alert("inside uploadcontroller");
$scope.submit = function(){
}
});
Please help me out as I'm stuck at this point for hours. Thank you in advance.
If you wan to save into a local file, there are several things you need to consider. First you have to modify your html part to eliminate the post section, because for a post you have to specify the url pointing too.
<div ng-controller="MyCtrl">
<div class="elem">
Upload a TXT File:<input id="fileForUpload" type="file" name="filename"/><br/>
<a ng-click="submit()" class="btn btn-md btn-primary" id ="downloadlink">Download</a>
</div>
</div>
Second, to save a file into the local system you need to use Blob which is an HTML5 feature. I've created a simple fiddle to point into the right direction.
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', ['$scope', function($scope) {
$scope.submit = function() {
var textFile = null;
var makeTextFile = function (text) {
var data = new Blob([text], {type: 'text/plain'});
// If we are replacing a previously generated file we need to
// manually revoke the object URL to avoid memory leaks.
if (textFile !== null) {
window.URL.revokeObjectURL(textFile);
}
textFile = window.URL.createObjectURL(data);
return textFile;
};
var file = document.getElementById("fileForUpload").files[0];
if (file) {
var reader = new FileReader();
reader.readAsText(file, "UTF-8");
reader.onload = function (evt) {
var link = document.getElementById('downloadlink');
link.href = makeTextFile(evt.target.result);
link.setAttribute('download', 'info.txt');
}
}
}
}]);
The javascript part can handle only txt file, but you can extend to any file type. You can find a lot of information on the net how you can do it.
Here is the fiddle:
http://jsfiddle.net/HB7LU/16576/
first create a directive to bind your uploaded files to model:
newController.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]);
});
});
}
};
}]);
Add following code :
<body>
<form action="go" method="post" enctype="multipart/form-data">
Select File:<input type="file" name="filename" file-model="myFile"/><br/>
<input ng-click="submit()" class="btn btn-md btn-primary"
type="submit" value="{{ 'UPLOAD' | translate }}" >
</input>
</form>
</body>
$scope.submit = function(){
var formData = new FormData();
formData.append('file', $scope.myFile);
$http({
url: "yourserverurl",
type: 'POST',
data: formData,
mimeType:"multipart/form-data",
contentType: false,
cache: false,
processData:false
});
};
please look at this link for more reference

Angular js Input type file - clear previously selected file

I am using input type="file" for my upload control using angular js. Everytime I click on browse, I do not want to see the previously selected file. By default,this seems to be retained. Can it be achieved by writing a directive? Can it be triggered everytime I click on browse?
I am using a bootstrap implementation to replace default browse button with some better.
<span class="useBootstrap btn btn-default btn-file">
Browse <input type="file" />
</span>
This was the easiest way, without using any directive or complex code.
Browse <input type="file" ng-click="clear()"
And in your controller
$scope.clear = function () {
angular.element("input[type='file']").val(null);
};
here is alternate way to clear input file type.
HTML ->>
`<span class="useBootstrap btn btn-default btn-file">
Browse <input type="file" ng-if="clearBtn" />
</span>`
Js ->>
`//initial loading
$scope.clearBtn = true;
// after submit / on reset function
$scope.submitform = function(){
//submit logic goes here;
//onsuccess function
$scope.clearBtn = false;
$timeout(function(){
$scope.clearBtn = true;
});
}`
If we use fileUpload directive, then we can clear uploaded file data directly from HTML.
e:g-
Directive -
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])
})
})
}
}
}])
html code- upload file input field
<button ng-disabled="!myFile" class="btn btn-primary btn-rounded btn-ef btn-
ef-5 btn-ef-5a mb-10 "
ng-click="uploadFile(myFile);myFile=''">Upload button
</button>
<button class="btn btn-danger btn-rounded btn-ef btn-ef-5 btn-ef-5a mb-10 "
ng-click="myFile=''">Clear
</button>
call http service
var fd = new FormData()
fd.append('file', file) //File is from uploadFile(myFile)
$http.post(url, fd, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined,
'sessionId': sessionId,
'project': userProject
}
})
You can do it very easily, here's an example:
<input type="file" accept="image/jpeg" id="fileInp" required file-input="files" >
//in my code the rest happens when a response is sent from the server
$http.post('upload.php', form_data,
{
transformRequest: angular.identity,
headers: {'Content-Type': undefined,'Process-Data': false}
}).success(function(response){
$scope.response_msg=response;
if($scope.response_msg=="File Uploaded Successfully")
{
$scope.IsVisibleSuccess = $scope.IsVisibleSuccess = true;
}
else
{
$scope.IsVisibleFailed=$scope.IsVisibleFailed=true;
}
$scope.img_name='';
$("input[type='file']").val('');
});

Resources