I am trying to crop-resize n display an image on client-browser using JS. I am able to do so except that my text loop is wrong. You can see in the image below that it is repeating the last iteration. My image loop works fine though. Hint - First filename text is supposed to be black.jpg.
Am unable to solve the issue after having tried for several hours. Given below is a trimmed version of the code. If needed here is the complete version of the script. Please help, I am still learning.
HTML
<input type="file" id="input" onchange="prevCrop()" multiple>
<ul id="listWrapper"></ul>
JAVASCRIPT
function prevCrop() {
var files = document.querySelector('input[type=file]').files;
for (var i = 0; i < files.length; i++) {
var file = files[i];
var fileSize = Math.floor(file.size/1024);
var info = file.name + " " + fileSize + " KB : iteration number - " + i;
var reader = new FileReader();
if (reader != null) {
reader.onload = GetThumbnail;
reader.readAsDataURL(file);
}
}
function GetThumbnail(e) {
var canvas = document.createElement("canvas");
var newImage = new Image();
newImage.src = e.target.result;
newImage.onload = cropResize;
function cropResize() {
canvas.width = 70;
canvas.height = 70;
### more codes here that handles image ###
var dataURL = canvas.toDataURL("image/jpg");
var thumbList = document.createElement('div');
thumbList.setAttribute('class', 'tlistClass');
var nImg = document.createElement('img');
nImg.src = dataURL;
var infoSpan = document.createElement('span');
infoSpan.innerHTML = info;
var handle = document.getElementById("listWrapper").appendChild(thumbList);
handle.appendChild(nImg);
handle.appendChild(infoSpan);
}
}
}
This happens because the onload callback function is triggered asynchronously, so after your code has already ended. At that time info has the string that was assigned to it in the last iteration. Only then the onload events are fired, resulting in the different calls of GetThumbnail, which all will see the same value for info.
Instead bind the value of info to the callback function like this:
reader.onload = GetThumbnail.bind(null, info);
...and define the corresponding parameter for it in the GetThumbnail function:
function GetThumbnail(info, e) {
That way every call of that function will posses of the proper value for info.
Related
var toPush = []
for(var i = 1; i <= myVariable; i++){
var variable1 = document.getElementById('q' + i).value;
var var2 = document.getElementById(i + 'x').value;
var var3 = document.getElementById(i + 'y').value;
var var4 = document.getElementById(i + 'z').value;
var var5 = document.getElementById(i + 'd1').value;
var var6 = document.getElementById('xy' + i).value;
var file = document.getElementById("fileup" + i);
var twofour = [var2, var3, var4, var5];
let reader = new FileReader();
reader.readAsDataURL(file.files[0]);
reader.onload = function () {
pictureURL = reader.result;
};
reader.onerror = function (error) {
console.log('Error: ', error);
};
toPush.push({"variable1": variable1, "twofour": twofour, "pictureURL": pictureURL}
}
The application can add X many inputs by appending them do div. When it comes to pushing the data, I want to have the file input, which is the only image input, be read as DataURL, so it can show be used as a source to an image preview. I don't know if it is because of the iteration, but the pictureURL variable pushes as empty: in the database I got "pictureURL": "".
Is there any way around it?
Thank you in advance.
There are multiple issues with this code. The reason that you're not receiving the pictureUrl is because you're reading it before it's ready.
FileReader reads the file asynchronously. It provides us a callback onload that is executed when it has read the file. We get the content of the file as reader.result only when this callback is executed. You have to rewrite your code to process the content of the file when it's either FileReader.onload or FileReader.onerror are executed.
See the working example below. I have removed unnecessary code. You can run the code by clicking on Run code snippet button at the bottom of the post
function showIcons() {
let files = document.querySelector('#files').files;
if(files.length) {
document.querySelector('#show-icons-error').textContent = "";
} else {
document.querySelector('#show-icons-error').textContent = 'No files have been selected';
}
let imageIcons = document.querySelector('#image-icons');
imageIcons.innerHTML = '';
let imageUrlArr = [];
for(var i = 0; i < files.length; i++) {
let imageIconHolder = document.createElement('img');
imageIconHolder.classList.add('image-icon');
imageIconHolder.setAttribute('image-index', i);
imageIcons.appendChild(imageIconHolder);
let file = files[i];
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
pictureURL = reader.result;
imageIconHolder.src = pictureURL;
imageUrlArr[i] = pictureURL;//Setting ith image, not pushing.
};
reader.onerror = function (error) {
console.log(`Error loading image at index : ${i}, error: ${error}`);
imageUrlArr[i] = error;//Error for ith image
};
}
}
.image-icon {
width: 10em;
display: block;
min-height: 5em;
}
<html>
<body>
<label for="files" class="btn">Select Images</label>
<input id="files" type="file" value="Select File" accept="image/*" multiple="multiple">
<br/>
<br/>
<div>
<button id="show-icons" onclick="showIcons()">Show Icons</button>
<span id='show-icons-error' style="color: red; font-weight: bold;"></span>
</div>
<br/>
<div id="image-icons">
</div>
</body>
</html>
So, as part of a little experiment, I need to access the binary data of a file, an image for example, as a string or array of 1s and 0s.
I read the documentation on the file reader, I'm attempting to use the readAsBinaryString method but it gives me a bunch of weird characters rather than what I'd normally think a string of binary should look like. Here's my code:
function handleFiles(files){
var selectedFile = files[0];
var reader = new FileReader();
reader.readAsBinaryString(selectedFile);
reader.onloadend = function () {
var result = reader.result;
store(result);
}
}
function store(data){
console.log('Storing data...');
console.log(data.slice(0, 1000));
}
As a web developer, I dont normally work with binary, so I'm probably fairly naive about this. Can someone explain how I get actual 1s and 0s?
I think I figured it out:
function handleFiles(files) {
var selectedFile = files[0];
var reader = new FileReader();
reader.readAsBinaryString(selectedFile);
reader.onloadend = function() {
var result = reader.result;
store(result);
};
}
function store(data) {
console.log("Storing data...");
var result = '';
data = data.slice(0, 1000)
for (var i1 = 0; i1 < data.length; i1++) {
result += data[i1].charCodeAt(0).toString(2) + " ";
}
console.log(result);
}
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 5 years ago.
I´m using fileReader to read the content of all selected files. After reading them with the fileReader API, I append the content to the DOM. That works perfectly.
It creates one p element per file.
Now I want to store each file content to local storage as well. Unfortunately, It stores only the last item. What´s going wrong? Thank you for your tips.
JS
$("input[name='uploadFile[]']").on("change", function() {
var files = !!this.files ? this.files : [];
if (!files.length || !window.FileReader)
return;
for (var i = 0; i < files.length; i++) {
(function(file) {
var name = file.name;
var reader = new FileReader();
reader.onload = function(e) {
var textObject = event.target.result.replace(/\r/g, "\n");
var textHTML = event.target.result.replace(/\r/g, "<br/>");
var text = e.target.result;
var p = document.createElement("p");
p.innerHTML = textHTML;
$('#results').append(p);
localStorage.setItem('letter'+ i, JSON.stringify(textObject));
};
reader.readAsText(file, 'ISO-8859-1');
})(files[i]);
}
});
The problem is that, by the time the onload is fired, i has been changed by the loop. This means that localStorage.setItem('letter'+ i will always refer to the last element in the array. You actually have the correct fix already in place -- the immediately invoked function expression -- but you need to add i as a parameter as well.
(function(file, index) {
var name = file.name;
var reader = new FileReader();
reader.onload = function(e) {
var textObject = event.target.result.replace(/\r/g, "\n");
var textHTML = event.target.result.replace(/\r/g, "<br/>");
var text = e.target.result;
var p = document.createElement("p");
p.innerHTML = textHTML;
$('#results').append(p);
localStorage.setItem('letter'+ index, JSON.stringify(textObject));
};
reader.readAsText(file, 'ISO-8859-1');
})(files[i], i);
There is also another solution if you can use let
let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.
Here is what it could look like:
for (let i = 0; i < files.length; i++) {
let file = files[i];
let name = file.name;
let reader = new FileReader();
reader.onload = function(e) {
var textObject = e.target.result.replace(/\r/g, "\n");
var textHTML = e.target.result.replace(/\r/g, "<br/>");
var text = e.target.result;
var p = document.createElement("p");
p.innerHTML = textHTML;
$('#results').append(p);
localStorage.setItem('letter'+ i, JSON.stringify(textObject));
};
reader.readAsText(file, 'ISO-8859-1');
}
I have an array of image elements,
var im = ["im1","im2"]; // from db or local drive
Then creating the images dynamically as:
var l = imagelist.length;
for (var i = 0; i < l; ++i) {
if (i in im) {
var s = im[i];
var img = document.createElement("img");
img.src = s;
img.width = width;
img.draggable = true;
var body = document.getElementById("body");
body.appendChild(img);
this.addEventListener('ondragstart', function(event) {
alert(event.target.id);
event.dataTransfer.setData('text/plain', event.target.id);
});
}
While the ondragstart event fires, but alert(event.target.id); shows blank.
That's the reason, the drag and drop functionality is not working for an array of images created dynamically .
Although tried dragging with a single image tag <img> which works absolutely fine, but the array of images doesn't work in this way.
Any solution for this?
You haven't assigned an id to any of your elements.
Something like this should do the trick:
var img = document.createElement("img");
img.src = s;
img.id = "image_" + i;
// The rest of your assignments and code...
I am attempting to create a basic Hangman program. It's an array of tags which are assigned into an array of Objects (called Buttons). Each image is an image of a letter, so for example you would press the 'L' button, it would check whether this was in an WordArray (which is an array of chars), then it would act accordingly (to hide the letter, then update the gallows image if it needed to).
I cannot get the onclick method of the images to access the checkinarray function. What am i doing wrong?
var LetterAmount = 3; //make this 26. checked.
var WordArray = new Array();
var Buttons = new Array();
function checkinarray(num){
var z = 0;
while (z<4){
document.write("looping through word now");
if (num == WordArray[z]){
document.write("<br/>it is in the word");
}
z++;
}
}
function ButtonClicked(){
this.Image.src = "images/blank.jpg";
checkinarray(this.Number);
}
function Button(Image, Number) {
this.Image = Image;
this.Number = Number;
this.ButtonClicked = ButtonClicked;
}
function initialiseletters(){
var x;
//set up empty img tags for use
for(i = 0; i < LetterAmount; i++) {
document.write("<img id=" + i + ">");
}
for(x = 0; x < LetterAmount; x++) {
document.images[x].src = "images/" + x + ".jpg";
document.getElementById(x).onclick =function(){
Buttons[this.id].ButtonClicked();
}
Buttons[x] = new Button(document.images[x], "" + x);
}
}
function initialiseword(){
//WordArray = new Array();
WordArray[0] = 0;
WordArray[1] = 1;
WordArray[2] = 2;
WordArray[3] = 3;
}
function initialise(){
initialiseword();
initialiseletters();
document.write("testing overall");
}
I'm not seeing a problem with ButtonClicked calling checkinarray, but I'm seeing a problem with checkinarray -- it's calling document.write after the page rendering is complete (e.g., when the user clicks), which won't work. You need to modify the DOM via DOM methods (this will be made much easier if you use a toolkit like Prototype, jQuery, MooTools, Dojo, the Closure Library, YUI, etc.).
document.getElementById(x).onclick =function(){
Buttons[this.id].ButtonClicked();
}
Is where your problem is. 'this.id' is undefined.
document.write is not a good way to add elements to the DOM... Try document.createElement('img');
Then you already have reference to the image like so:
var img = document.createElement('img');
img.onclick = function()
{
//your click...
}
//add it to the view stack
document.body.appendChild(img);