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
Related
I'm trying to pass a zip code to a service that runs an API call using this zip. The problem is, every time I enter a zip and search, the zip code is not passed to the service properly and my HTTP request sends with the zip code as undefined.
Here is my controller:
angular.module('MainCtrl', []).controller('MainController', ['$scope', 'Reps', function($scope, Reps) {
$scope.search = function() {
Reps.search($scope.zipCode)
.success(function(response) {
console.log('Success ' + response);
})
.failure(function(response) {
console.log('Failure ' + response);
})
}
}]);
My service:
angular.module('MainService', []).factory('Reps', ['$http', function($http) {
var root = 'https://www.api.com/locate?';
var apiKey = '&apikey=foo';
var fields = '&fields=bar';
return {
search: function(zipCode) {
var query = root + zipCode + apiKey + fields;
return $http({
method: 'POST',
url: query
})
}
}
}])
My form:
<form method="post" enctype="text/plain" class="form-inline">
<div class="form-group">
<label for="searchForRep">Zip Code:</label>
<input type="text" class="form-control" id="searchForRep" ng-model="zipCode" placeholder="Zip Code (11216)">
</div>
<button ui-sref="reps" ng-click="search()" type="submit" class="btn btn-default">Submit</button>
</form>
So, as mentioned, the zip code does not seem to pass to my service correctly, which is causing the HTTP request to send as:
https://www.api.com/locate?undefined&apikey=foo&fields=bar
Any idea what the issue is with my code?
As per your code it should work. It is working on my plunker, except you did not add your service module to your controller module like:
angular.module('MainCtrl', ['MainService']).controller('MainController',
Plunker here: http://plnkr.co/edit/Ey3K5eF5h56dqWTji5uX?p=preview
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?
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('');
});
I need to override the default functionality of the image insert button of the textAngular.
I need to open a modal on the click of the same. How to do this?
I had a similar problem and found it wasn't documented super well. There are a few bug threads where some solutions are mentioned:
https://github.com/fraywing/textAngular/issues/54 and
https://github.com/fraywing/textAngular/issues/146
Following another user's solution there, and the customizing the toolbar section on the wiki, my solution looked like this:
config(['$provide',
function($provide) {
$provide.decorator('taOptions', ['taRegisterTool', '$modal', '$delegate',
function(taRegisterTool, $modal, taOptions) {
// $delegate is the taOptions we are decorating
// here we override the default toolbars specified in taOptions.
taOptions.toolbar = [
['clear', 'h1', 'h2', 'h3'],
['ul', 'ol'],
['bold', 'italics'],
['insertLink', 'insertVideo']
];
// Create our own insertImage button
taRegisterTool('customInsertImage', {
iconclass: "fa fa-picture-o",
action: function($deferred) {
var textAngular = this;
var savedSelection = rangy.saveSelection();
var modalInstance = $modal.open({
// Put a link to your template here or whatever
template: '<label>Enter the url to your image:</label><input type="text" ng-model="img.url"><button ng-click="submit()">OK</button>',
size: 'sm',
controller: ['$modalInstance', '$scope',
function($modalInstance, $scope) {
$scope.img = {
url: ''
};
$scope.submit = function() {
$modalInstance.close($scope.img.url);
};
}
]
});
modalInstance.result.then(function(imgUrl) {
rangy.restoreSelection(savedSelection);
textAngular.$editor().wrapSelection('insertImage', imgUrl);
$deferred.resolve();
});
return false;
},
});
// Now add the button to the default toolbar definition
// Note: It'll be the last button
taOptions.toolbar[3].push('customInsertImage');
return taOptions;
}
]);
}
]);
Check out the plunkr!
Major gotcha: This may be evident to others, but you need the restore selection stuff for the image insert to work. I guess execCommand puts the image at the cursor position, and that position is lost when you open up your own modal. I'm not sure if rangy specifically is necessary, or if you could just make sure the editor has cursor focus first before calling wrapSelection.
Edit: If you're importing the rangy library, textAngular has an optional method in the action constructor for it. Docs: "restoreSelection is only defined if the rangy library is included and it can be called as restoreSelection() to restore the users selection in the WYSIWYG editor." So your action method can use it instead of direct rangy calls.
action: function($deferred, restoreSelection) {
var textAngular = this;
var modalInstance = $modal.open({
....
});
modalInstance.result.then(function(imgUrl) {
restoreSelection();
textAngular.$editor().wrapSelection('insertImage', imgUrl);
$deferred.resolve();
});
return false;
},
});
...
Im' sharing the code for an image upload service I implemented through angular-bootsrap-ui $modal service and DanialFarid's angular-file-upload service.
.config(function ($provide) {
$provide.decorator('taOptions', ['taRegisterTool', '$delegate', '$modal', function (taRegisterTool, taOptions, $modal) {
taRegisterTool('uploadImage', {
iconclass: "fa fa-image",
action: function (deferred) {
$modal.open({
controller: 'UploadImageModalInstance',
templateUrl: 'views/modals/upload.html'
}).result.then(
function (result) {
document.execCommand('insertImage', true, result);
deferred.resolve();
},
function () {
deferred.resolve();
}
);
return false;
}
});
taOptions.toolbar[1].push('uploadImage');
return taOptions;
}]);
})
Now the view for the modal with the button that handles the $scope.upload() function, previews the uploaded image, and a button that fires the $scope.insert() function.
<form data-ng-submit="insert()">
<div class="modal-header">
<div class="col-md-10">
<h4 class="modal-title"><span class="glyphicon glyphicon-picture"></span> Upload Image</h4>
</div>
<div class="col-md-2 right">
<a class="close" href data-ng-click="$dismiss()"><span class="glyphicon glyphicon-remove"></span></a>
</div>
</div>
<div class="modal-body">
<img data-ng-src="{{image}}">
<progressbar data-ng-show="progress > 0 && progress < 100" class="progress-striped active" value="progress"></progressbar>
</div>
<div class="modal-footer center clearfix">
<button data-ng-click="$dismiss()" type="button" class="btn btn-default pull-left">Cancel</button>
<button type="submit" data-ng-disabled="image == null || image == '' || image == 'img/posts/default.svg'" class="btn btn-primary pull-right">Insert Image</button>
<button type="button" data-ngf-select data-ngf-change="upload()" data-ng-model="files" data-ngf-multiple="false" class="btn btn-primary pull-right"><span class="glyphicon glyphicon-picture mR5"></span>Upload Image</button>
</div>
</form>
And also the controller that handles the file upload and image insert:
app.controller('UploadImageModalInstance', function($scope, $modalInstance, Upload){
$scope.image = 'img/default.png';
$scope.progress = 0;
$scope.files = [];
$scope.upload = function(){
Upload.upload({
url: 'api/upload',
fields: {'dir': 'img/uploads/'},
file: $scope.files[0],
method: 'POST'
}).progress(function (evt) {
$scope.progress = parseInt(100.0 * evt.loaded / evt.total);
}).success(function (data) {
$scope.progress = 0;
$scope.image = data.dir+data.filename;
});
};
$scope.insert = function(){
$modalInstance.close($scope.image);
};
})
I am new to AngularJS and not sure where I am missing, though I know its a minor mistake which I am committing. Please help me out with below scenario.
I have a form where in I write a post {textArea} and click submit button, which calls ng-click=createPost() method.
It goes to controller.js which is:
app.controller('MyCtrl1', ['$scope', 'PostFactory', '$location', function ($scope, PostFactory, $location) {
/* callback for ng-click 'createUser': */
$scope.createPost = function() {
alert("in createPost" + $scope.post.postText);
alert("in createPost" + $scope.post);
PostFactory.create($scope.post)
$scope.posts.push($scope.post.postText);
$scope.post = "";
$location.path('/view1');
}
$scope.posts = PostFactory.query();
/*UserFactory.get({}, function (userFactory) {
$scope.firstname = userFactory.firstName;
})*/
}]);
and my service.js is:
var services = angular.module('ngdemo.services', ['ngResource']);
//alert("In services");
services.factory('PostFactory', function ($resource) {
// alert("Reached services.js");
return $resource('/ngdemo/web/posts', {}, {
query: {
method: 'GET',
//params: {},
isArray: true
},
create: {method: 'POST'}
})
});
my Spring controller which is exposed as service and have post method:
#RequestMapping(/*value = "/add",*/ method = RequestMethod.POST)
public #ResponseBody String addPost(#ModelAttribute(value = "") Post post, BindingResult result) {
System.out.println("Post value : " + post.getPostText());
//post.setPostId();
post.setPostTags("#dummy");
postService.addPost(post);
return "redirect:/";
}
my form :
<form novalidate="novalidate" class="form-horizontal">
<!-- Textarea -->
<div class="form-group">
<div class="col-md-4">
<textarea ng-model="post.postText" rows="4" cols="300" name="inputQuestion" id="post.postText" class="form-control expand" placeholder="What you want to pingle today?"></textarea>
</div>
<br>
<!-- Button -->
<div class="col-md-4">
<button ng-click='createPost()' class="btn btn-default plus"> Pingle it! </button>
</div>
</div>
</form>
Problem is : always Post value in controller is coming as null, have tried with $scope.post and $scope.postText but no joy!
Please let me know where I am missing?????
UPDATE:
How can we pass a form object to Spring Controller in controller.js?? Post is my Domain object
it worked, once I replaced #ModelAttribute with #RequestBody, somehow it was preventing the data to be populated in my object. After setting #RequestBody, it worked!Thanks all!