Getting around Typescript with ngImgCrop - javascript

I'm new to coding and have the opportunity to do some small stories on a project to whet my teeth. Right now I'm working on getting profile picture selection and cropping into a webapp with AngularJS. I've selected ngImgCropper to handle the cropping. Here's a JSFiddle with boilerplate code: http://jsfiddle.net/a2ew3yhf/50/
And here's JavaScript from that link:
var handleFileSelect=function(evt) {
var file=evt.currentTarget.files[0];
var reader = new FileReader();
reader.onload = function (evt) {
$scope.$apply(function($scope){
$scope.myImage = evt.currentTarget.result;
});
};
reader.readAsDataURL(file);
};
Here's my problem. My project uses Typescript, which doesn't support evt.currentTarget.result, so I get the following error:
Property 'result' does not exist on type 'EventTarget'
Is there any way to get around this?

Simple solution
If you sure that this property exist just make something like below
var handleFileSelect=function(evt) {
var file=evt.currentTarget.files[0];
var reader = new FileReader();
reader.onload = function (evt) {
$scope.$apply(function($scope){
$scope.myImage = (<any>evt.currentTarget).result;
});
};
reader.readAsDataURL(file);
};
Also you can create own interface that would be describe your target
interface MyTarget {
result:any; //or type of image
}
//skip some code
$scope.myImage = (evt.currentTarget as MyTarget).result;
Complicated solution
You can provide own declaration of ngImageCroper or provide description for current event
var handleFileSelect=function(evt: ImageCropEvent){
//your stuff
}
Resource
Write your d.ts file

Related

Uncaught TypeError: this.files is undefined thrown by fr.readAsText(this.files[0]) (FileReader)

I am experiencing an unexpected error when trying to load a javascript object using FileReader, unexpected because it works fine in another project, which is listed below. My intention is to perform a few operations on the javascript object right after reading it by executing a function that has several parameters, and that's why I changed the code structure because I didn't know how to put parameters in the code that works. Any tips are welcome.
Code that doesn't work
function wczytajSklad(sklad, id, objSklad, gdzie) {
var fr = new FileReader();
fr.onload = function(){
let wczytanySklad = fr.result;
sklad = JSON.parse(wczytanySklad);
ukryjInputFile(id);
pokazCheckAndRadio(objSklad, gdzie);
}
fr.readAsText(this.files[0]);
}
A place where i try to run function
<input type="file" name="gospodarze" id="wczytajSkladGospodarzy" onchange="wczytajSklad(skladGospodarzy, 'wczytajSkladGospodarzy', skladGospodarzy, 'skladGospodarzy')">
Code that works
document.getElementById('inputfile')
.addEventListener('change', function() {
var fr = new FileReader();
fr.onload = function(){
wczytanyPlik = fr.result;
arrPoints = JSON.parse(wczytanyPlik);
rysuj();
}
fr.readAsText(this.files[0]);
})

JavaScript object to file object

I'm working on adding images to page, do something with collection of added images (preview etc) and finally I want them save. Everything is cool until the files object is used to show or save the photo.
var input = document.getElementById('files');
var files = input.files;
as it is an array of objects read only - it is impossible to manipulate it freely. For working with that array friendly I maped it like that:
var addedFiles = added(files);
function added(from) {
return $.map(from, function (i) {
var x = { lastModified: i.lastModified, lastModifiedDate: i.lastModifiedDate, name: i.name, size: i.size, type: i.type, webkitRelativePath: i.webkitRelativePath }
return x;
});
}
... then do something with those files - and I want to preview, and then save - but for example during preview I get an error:
Uncaught TypeError: Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'.
function readImage(file) {
var reader = new FileReader();
reader.addEventListener("load", function () {
var image = new Image();
image.addEventListener("load", function () {
preview.innerHTML += drawHtml(this, file);
window.URL.revokeObjectURL(image.src); //blob version
});
image.src = reader.result; //file version
image.src = window.URL.createObjectURL(file) //blob version
});
reader.readAsDataURL(file); // here fire the error
}
When I pass for testing originally file obj to above code every thing is working.
Question:
How to create custom obj (in my case array of obj) that can be parse to file obj
P.S. In project I'm using jquery and javascript
Rather than mapping the File objects to new, incompatible objects, you could instead wrap them with the additional things you need, but then use the underlying original files when reading them:
const fileSelections = Array.prototype.map.call(input.files, file => ({
// This will let you get to the underlying file in the wrapper objects
file,
// If you want pass-throughs, you can do stuff like this:
get lastModified() { return file.lastModified },
// And you can add your own properties/methods as you please
});
function readImage(fileSelection) {
// Unwrap the file
const file = fileSelection.file;
const reader = new FileReader();
reader.addEventListener("load", function () {
const image = new Image();
image.addEventListener("load", function () {
preview.innerHTML += drawHtml(this, file);
window.URL.revokeObjectURL(image.src); //blob version
});
image.src = reader.result; //file version
image.src = window.URL.createObjectURL(file) //blob version
});
reader.readAsDataURL(file);
}
correct answer is blob - it's something amazing for me.
//from is the array of obj - files
function added(from) {
var out = [];
for (var i = 0; i < from.length; i++) {
(function (obj) {
var readerBase64 = new FileReader();
var obj = from[i];
readerBase64.addEventListener("load", function () {
var fileBase64 = readerBase64.result;
var row = { name: obj.name, size: obj.size, type: obj.type, base64: fileBase64 }
out.push(row);
});
readerBase64.readAsDataURL(obj);
})(from[i]);
}
return out;
}
'out' is a table of my own objects with base64, so I can create images for preview and 'do something functions' in the end I'm going to use base64 for create files.
here link for question related to my next step - creating img from blob (where I'm using additional lib b64toBlob)

Image in localstorage function doesn't work

I'm wrting a function which takes an image from a file input from a form and enables me to put it in localstorage. The function I wrote to achieve this:
function getImage() {
var pic = document.getElementById("image").files[0];
var imgUrl;
var reader = new FileReader();
reader.onload = function(e) {
var imgURL = reader.result;
saveDataToLocalStorage(imgURL);
return imgUrl;
}
}
Then in another function I call this function and create a JSON entry in which I store values from other form inputs including the image. It looks like this:
var imgUrl = getImage();
// Create new JSON entry
var json_entry = {'title': titleField.val(),
'image': imgUrl,
'content': contentField.val(),
'location': location};
Sadly the value of imgUrl is undefined.. There are no console errors. What am I doing wrong? And how can I fix this?
I honestly don't know much about the FileReader object, but I can see just from glancing at your JS that (at least) one thing is off:
var imgUrl = getImage();
Your getImage function doesn't return anything; so imgUrl is definitely going to be undefined above.
If you want to do something with the result property of your FileReader, then you need to do so w/ a callback since you're handling the (asynchronous) onload event:
function getImage(callback) {
// What are you doing with this?
var pic = document.getElementById("image").files[0];
var reader = new FileReader();
reader.onload = function(e) {
var imgURL = reader.result;
saveDataToLocalStorage(imgURL);
// Note the difference here: rather than return from the event handler
// (which effectively does nothing) we pass the result to a callback.
callback(imgUrl);
}
// I assume you actually need to load something with the FileReader?
}
And then:
getImage(function(imgUrl) {
var json_entry = {
'title': titleField.val(),
'image': imgUrl,
'content': contentField.val(),
'location': location
};
});
It looks like you are forgetting to set the reader to readAsDataUrl. Likely the value is coming back as undefined because localStorage does not inherently know how to serialize binary data. Setting the reader to readAsDataUrl changes reader.result onload.
var reader = new FileReader();
reader.onload = function(e) {
var imgURL = reader.result;
saveDataToLocalStorage(imgURL);
callback(imgUrl);
};
// add this line
reader.readAsDataURL(pic);
Have a look at this article, especially the section titled Reading Files. Note in the linked example the author uses e.target.result instead of reader.result. This should be the same value.

Passing file contents to outside variable

I'm using a FileReader and the HTML file dialog to read a file in my script. How do I pass this file's contents out of the FileReader.onload function?
function readFileData(evt) {
var file = evt.target.files[0];
var reader = new FileReader();
reader.onload = function(e) {
var contents = e.target.result;
}
reader.readAsText(file);
}
document.getElementById('file').addEventListener
('change', readFileData, false);
/* I want to access the contents here */
I tried sticking returns in the readFileData and onload functions, but I'm not sure what they return to.
I assume that you know, its async and all.
So, the short answer is: No, you can not do that.
However, if you want the contents to be globally accessible for any future calls, you could something like this:-
var contents;// declared `contents` outside
function readFileData(evt) {
var file = evt.target.files[0];
var reader = new FileReader();
reader.onload = function(e) {
contents = e.target.result; //<-- I removed the `var` keyword
}
reader.readAsText(file);
}
document.getElementById('file').addEventListener('change', readFileData, false);
var reasonableTimeToWaitForFileToLoad = 100000;
console.log(contents); //`contents` access first attempt: prints undefined
setTimeout(function() {
console.log(contents);//`contents` access second attempt: prints the contents 'may be if the time allows.'
}, reasonableTimeToWaitForFileToLoad);
var contents;
function readFileData(evt) {
var file = evt.target.files[0];
var reader = new FileReader();
reader.onload = function(e) {
contents = e.target.result;
}
reader.readAsText(file);
reader.onloadend=function(e) {
console.log(contents)
}
}
document.getElementById('file').addEventListener('change', readFileData, false);
This is a scoping issue. When you're declaring contents within the onload, it's no longer available after that function has run. You need to declare contents outside of that scope first.
var contents;
function readFileData(evt) {
var file = evt.target.files[0];
var reader = new FileReader();
reader.onload = function(e) {
contents = e.target.result;
}
reader.readAsText(file);
}
document.getElementById('file').addEventListener
('change', readFileData, false);
//make changes here
//contents should have the correct value
Firstly, you have to realize that reading a file with a FileReader is an asynchronous task, and you cannot work with it in a synchronous manner.
There are many ways to handle this, but many of them are not suited for recommendations ;)
I would do it one of these 2 ways:
1: you can call a function from within the onload event handler and pass the file contents as a parameter
2: you can trigger an event from within the onload event handler and pass the file contents as event data
Just declare contents outside both functions and assign to it inside the inner function:
var contents;
var outer_fn = function() {
var inner_fn = function() {
contents = '42';
}
inner_fn();
}
outer_fn();
// here, `contents' is '42'
I faced a similar challenge and this is what I used to solve the issue.
var contents;
function readFileData(evt) {
var file = evt.target.files[0];
var reader = new FileReader();
reader.onload = function(e) {
contents = e.target.result;
}
reader.readAsText(file);
//calling to access the 'contents' variable
accessFileContents();
}
document.getElementById('file').addEventListener('change', readFileData, false);
var wait4file2load = 1000;
/* To access 'contents' here */
function accessFileContents(){
setTimeout(function(){
console.log(contents);
}, wait4file2load);
}
It won't give undefined value since we are calling it after the file is completely uploaded.
I had a similar problem in Angular 7 (typescript), and this is how I solved my problem.
What I wanted to do was to access the base64 conversion that was happening inside fileReader -> reader.onload
Then pass that parameter to another method where I could convert it to a JSON object then post it to the API seeing I want to post another parameter as well in the post. (not added in this code)
What I did first was to declare what I potentially needed to access outside the Method that.
base: any = null;
base64File: any = null;
fileToTest: any = null;
Then I converted the pdf to base64 when the upload event fired
convertToBase64 (e){
this.fileToTest = e.target.files[0];
var reader = new FileReader();
reader.onload = () => {
this.base64File = reader.result.slice(28);
};
reader.onerror = function (error) {
console.log('Error: ', error);
}.bind(this.base64File);
reader.readAsDataURL(this.fileToTest);
return this.base64File;
}
Finally access the base64 file in the other method
onSubmit() {
console.log("base 64 file is visible", this.base64File);
var base =
{
"FileBase64": this.base64File,
"Path": "document",
"FileType": ".pdf"
};
console.log("JSON object visible", base);
this.uploadService.base64Post(base);
}
Everything works now, and hopefully maybe this can help someone else finding themselves with the same problem.
Using Angular 7, code is in the component file, and the post function is in the Service file. Without my comments the code is exactly like this in the component file.

HTML5 File API: get File object within FileReader callback

With the new File API in Javascript you can read files in Javascript to create dataURLs to show clientside pictures clientside. I'm wondering if you can reach the File object within the FileReader's onload callback.
I will illustrate this with an example:
var div = document.createElement('div');
div.ondrop = function(e) {
e.preventDefault();
e.stopPropagation();
var files = e.dataTransfer.files;
for ( var i=0; i<files.length; i++ ) {
var file = files[i]; // this is the file I want!!
var filereader = new FileReader();
filereader.onload = function(e) {
this; // the FileReader object
e.target; // the same FileReader object
this.result; // the dataURL, something like data:image/jpeg;base64,.....
var img = document.createElement('img');
img.src = this.result;
img.title = file.fileName; // This won't be working
document.appendChild(img);
}
}
return false;
}
What I could do - what I do right now - is wrap the contents of the for loop in a function and execute it to create a new scope and keep a file in that scope like so:
for ( var i=0; i<files.length; i++ ) {
var _file = files[i]; // this is the file I want!!
(function(file) {
// do FileReader stuff here
})(_file);
}
I was just wondering... Maybe I'm missing something. Is there a way to get the File object from within the onload function of the FileReader? Both this and e.target are the FileReader object and not the File. Is there something in this or e that is the File?? I can't find it :(
Thanks a bunch.
PS. A fiddle: http://jsfiddle.net/rudiedirkx/ZWMRd/1/
I already found a way. Maybe not better than the scope wrapper, but I think it's neater:
for ( var i=0; i<files.length; i++ ) {
var file = files[i]; // this is the file I want!!
var filereader = new FileReader();
filereader.file = file;
filereader.onload = function(e) {
var file = this.file; // there it is!
// do stuff
}
}
There is now a much easier (apparently faster) way (sync!) to get a file's data URL:
img.src = URL.createObjectURL(file);
Demo on http://jsfiddle.net/rudiedirkx/ZWMRd/8/show/ of both methods, and the original problem illustrated (drag multiple images and check the title tooltips).
I don't think this.file is still supported. When I try to run the answer code, this.file is undefined whereas if I run the code from the question I get the expected results. I think you have to use the closure (at least this is how they do it on html5rocks (Example)).

Categories

Resources