I'm creating a webapp which features uploads of .csv file.
Instead of uploading the whole file on my server, then adding every lines in a table thanks to PHP, I'd like to parse the file in Angular, then add parsed lines (thanks to Restangular). This way, I should be able to retrieve some "errors" before uploading them (or not).
In a view, I've created a simple file input, with a directive called file (source : http://angularjstutorial.blogspot.fr/2012/12/angularjs-with-input-file-directive.html)
<input type="file" data-file="param.file" />
The filedirective :
app.directive('file', function(){
return {
scope: {
file: '='
},
link: function(scope, el, attrs){
el.bind('change', function(event){
var files = event.target.files;
var file = files[0];
scope.file = file ? file.name : undefined;
scope.$apply();
});
}
};
});
This way, I can retrieve when the user chooses a file. Unfortunately, I'm getting only the file name.
I'd like to parse the csv in a string, which i'll split thanks to this filter (source : parsing CSV in Javascript and AngularJS) :
app.filter('csvToObj',function(){
return function(input){
var rows=input.split('\n');
var obj=[];
angular.forEach(rows,function(val){
var o=val.split(';');
obj.push({
designation:o[1],
...
km:o[11]
});
});
return obj;
};
});
How can I retrieve the data in the csv file provided by the input instead of the file name ?
Thanks in advance.
Ok, I found the solution by searching on existing modules to upload files. I just post it here if this interests someone.
In the view, I've changed the directive to trigger the event :
<input type="file" file-change="handler($event,files)" ng-model="MyFiles" />
The directive is now :
app.directive('fileChange',['$parse', function($parse){
return{
require:'ngModel',
restrict:'A',
link:function($scope,element,attrs,ngModel){
var attrHandler=$parse(attrs['fileChange']);
var handler=function(e){
$scope.$apply(function(){
attrHandler($scope,{$event:e,files:e.target.files});
});
};
element[0].addEventListener('change',handler,false);
}
}
}]);
In the controller (don't forget to add $filter in the controller if you want to use it) :
$scope.MyFiles=[];
$scope.handler=function(e,files){
var reader=new FileReader();
reader.onload=function(e){
var string=reader.result;
var obj=$filter('csvToObj')(string);
//do what you want with obj !
}
reader.readAsText(files[0]);
}
The filter is still the same (except I've shifted the rows array to not import the header of my csv files).
Related
I'm trying to get AngularJS to trigger a file download when a user clicks on a button.
The file that should download has to contain data that is generated during the script execution, so the text file's content should be built from a basic string in AngularJS.
How do I implement this?
Here is some mockup code on how I imagine this would work:
var fileContent = 'foobar';
$scope.download = function() {
filedownload.run(fileContent, 'filename.txt');
}
In order to achieve this you have to create an a tag in your HTML:
<a download="content.txt" ng-href="{{ url }}">download</a>
Controller:
var content = 'file content for example';
var blob = new Blob([ content ], { type : 'text/plain' });
$scope.url = (window.URL || window.webkitURL).createObjectURL( blob );
And to enable the URL:
app = angular.module(...);
app.config(['$compileProvider',
function ($compileProvider) {
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|file|blob):/);
}]);
Source:
How do you serve a file for download with AngularJS or Javascript?
In simple cases, you can create a link with a Data URI:
var fileContent = 'foobar';
$scope.download = 'data:text/plain;base64,' + btoa(fileContent);
And then use it in your HTML template:
click here to download
You may need to adapt the MIME type, depending on your string.
I am using Angular js with ASP.NET MVC and file upload done using codepen method.
It is running fine because I want to store the binary array so I can convert later and set it back.
But the problem I am facing is to validate the selected thing is image or not!
I can't find the way how can I check the selected thing is image or not?
Anyone have any idea about this?
I have also used parsley js for validation but it is angular js here also how can I use parsley to validate the selected thing is image or not or manually?
angular.module('starter', [])
.controller('Ctrl', function($scope) {
$scope.data = {}; //init variable
$scope.click = function() { //default function, to be override if browser supports input type='file'
$scope.data.alert = "Your browser doesn't support HTML5 input type='File'"
}
var fileSelect = document.createElement('input'); //input it's not displayed in html, I want to trigger it form other elements
fileSelect.type = 'file';
if (fileSelect.disabled) { //check if browser support input type='file' and stop execution of controller
return;
}
$scope.click = function() { //activate function to begin input file on click
fileSelect.click();
}
fileSelect.onchange = function() { //set callback to action after choosing file
var f = fileSelect.files[0], r = new FileReader();
if(f.type === 'image/jpeg' || f.type === 'image/png') {
console.log('The file type is ' + f.type);
// do something here
} else {
console.log('The file type is ' + f.type);
// do some other thing here
}
r.onloadend = function(e) { //callback after files finish loading
$scope.data.b64 = e.target.result;
$scope.$apply(); console.log($scope.data.b64.replace(/^data:image\/(png|jpg);base64,/, "")); //replace regex if you want to rip off the base 64 "header"
//here you can send data over your server as desired
}
r.readAsDataURL(f); //once defined all callbacks, begin reading the file
};
});
or you can dynamically set accept="image/*" attribute to your html element.
check here
User uploads the pdf file which gets saved to mongo as a binary, files are small in size (<1mb) so I am not using GridFS.
How to download the pdf back?
Here is what I have tried:
I am extracting the binary from mongo and sending it back to the user. I am using Hapi, sending it back goes simply as
res(binaryMongoPDF).code(200);
I am receiving same data I have store in mongo on the client. According to what I have read I should convert the binary to blob:
var blob = new Blob([data], { type: 'application/pdf' });
I have tried with and without setting responseType to arraybuffer:
$http.get(API_URL + "/cv/me", {responseType:'arraybuffer'})
and then just let user download it, I am simplifying that with Angular FileSave, but I have also tried with vanilla a tag creation approach:
FileSaver.saveAs(r, 'text.pdf');
The file I am getting back can't be opened as a pdf.
Something I have observed is that binary file I am saving in mongo has size 73262, but the blob has size 97426. I have no idea if this is normal or not.
If the server returns the file as a data url:
data:application/octet-stream;base64,iVBORw0KGgoAAAANSUhEUgA
Use this directive:
angular.module("myApp").directive("xdHref", function() {
return function linkFn (scope, elem, attrs) {
scope.$watch(attrs.xdHref, function(newVal) {
newVal && elem.attr("href", newVal);
});
};
});
To set the href attribute of an <a> tag with the data:
<a download="data_{{files[0].name}}" xd-href="data">
<button>Download data</button>
</a>
The DEMO on PLNKR
Is there a way to get name, path and size of selected file in input field using angularJS,
before uploading it?
<input type="file" ng-model="fileContent" on-read-file="showContent($fileContent)" />
$scope.showContent = function($fileContent){
$scope.content = $fileContent;
};
Can anyone help to solve this please?
The HTML5 File API will give you a File object for each file that you're attempting to upload. This File object will have a size and name property which will give you the file size in bytes and the name of the file.
There's no property for the physical path to the file on the users machine, though.
You can read more about this on MDN: https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications
More information on the File object here: https://developer.mozilla.org/en-US/docs/Web/API/File
Here's a working example: http://jsfiddle.net/fmeLz9cd/
Given an input of type file with an id fileSelected, here's an example of accessing the properties through the File API:
$('#fileSelected').on('change', function (evt) {
var files = $(evt.currentTarget).get(0).files;
if(files.length > 0) {
$('#fileName').text(files[0].name);
$('#fileSize').text(files[0].size);
$('#filePath').text($('#fileSelected').val());
}
});
Update
Since you've requested an AngularJS specific example, here's the same code working in an angular app:
http://jsfiddle.net/vyc6jq84/1/
<div ng-app="fileDemo">
<input type="file" fd-input />
</div>
var app = angular.module('fileDemo', []);
app.directive('fdInput', [function () {
return {
link: function (scope, element, attrs) {
element.on('change', function (evt) {
var files = evt.target.files;
console.log(files[0].name);
console.log(files[0].size);
});
}
}
}]);
You cannot, unless the server helps. Angular is running in your browser, and cannot read the filesystem of the server or of the browser's computer. If you want to get a file, you need the server to implement something that will do so.
Now, if it is a static file, and already is served up by the server, then you could read it via $http.
$http.get(filename).success(function(data){
// data contains the file content
});
But it may be interpreted based on the file type, etc. And this entirely presumes the file is already being served by the server.
I was actually looking to get the content of clipboard using angular JS to simulate a copy paste thing.
I created a directive for copy to clipboard which is using the document.execCommand() method.
Directive
(function() {
app.directive('copyToClipboard', function ($window) {
var body = angular.element($window.document.body);
var textarea = angular.element('<textarea/>');
textarea.css({
position: 'fixed',
opacity: '0'
});
function copy(toCopy) {
textarea.val(toCopy);
body.append(textarea);
textarea[0].select();
try {
var successful = document.execCommand('copy');
if (!successful) throw successful;
} catch (err) {
console.log("failed to copy", toCopy);
}
textarea.remove();
}
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.bind('click', function (e) {
copy(attrs.copyToClipboard);
});
}
}
})
}).call(this);
Html
<button copy-to-clipboard="Copy Me!!!!" class="button">COPY</button>
here's a concise version I use -
function copyToClipboard(data) {
angular.element('<textarea/>')
.css({ 'opacity' : '0', 'position' : 'fixed' })
.text(data)
.appendTo(angular.element($window.document.body))
.select()
.each(function() { document.execCommand('copy') })
.remove();
}
BTW, if using Angular to copy to clipboard with a Chrome Packaged App, do the following:
Add "clipboardRead" and "clipboardWrite" to the "permissions" in the manifest.json.
use ng-click in your view to feed the value to the controller $scope, like: data-ng-click="copyUrlToClipboard(file.webContentLink)"
Put a function in your controller like:
$scope.copyUrlToClipboard = function(url) {
var copyFrom = document.createElement("textarea");
copyFrom.textContent = url;
var body = document.getElementsByTagName('body')[0];
body.appendChild(copyFrom);
copyFrom.select();
document.execCommand('copy');
body.removeChild(copyFrom);
this.flashMessage('over5');
}
I had the same issue and I used angular-clipboard feature[1] which uses new Selection API and Clipboard API available in the latest browsers.
First we have to install angular-clipboard lib, i'm using bower.
$ bower install angular-clipboard --save
To import the module use following in html.
<script src="../../bower_components/angular-clipboard/angular-clipboard.js"></script>
To set values to element using $scope in controller
$scope.textToCopy = 'Testing clip board';
Load the clipboard module using,
angular.module('testmodule', ['angular-clipboard']);
This works for Chrome 43+, Firefox 41+, Opera 29+ and IE10+.
Its simple & worked fine.
[1] https://www.npmjs.com/package/angular-clipboard
Thanks,
A completely different approach:
I need to copy & paste text between windows, so I used this to save (copy) the data to local storage. Then, in the other window, I load it out of local storage, using the same key, and I can then 'paste' is as I like.