I think my javascript in my php file is in conflict with my javascript file.
I have a script that checks of the image is smaller then 2MB and a script that shows the image you selected in a small version. But the second part does not work when the first script is active. how do I fix this?
script in HTML
<script>
window.onload = function() {
var uploadField = document.getElementById("frontImages");
uploadField.onchange = function() {
if(this.files[0].size > 2000000){
alert("File is too big!");
this.value = "";
};
};
var uploadField = document.getElementById("itemImages");
uploadField.onchange = function() {
if(this.files[0].size > 200){
alert("File is too big!");
this.value = "";
};
};
}
</script>
.js file
$("#frontImages").change(function () {
if ($('#frontImages').get(0).files.length > 0) {
$('#frontImages').css('background-color', '#5cb85c');
} else {
$('#frontImages').css('background-color', '#d9534f');
}
});
$("#itemImages").change(function () {
if ($('#itemImages').get(0).files.length > 0) {
$('#itemImages').css('background-color', '#5cb85c');
} else {
$('#itemImages').css('background-color', '#d9534f');
}
});
document.getElementById("frontImages").onchange = function () {
var x = document.getElementById('previewFrontImage');
x.style.display = 'block';
var reader = new FileReader();
reader.onload = function (e) {
document.getElementById("previewFrontImage").src = e.target.result;
};
reader.readAsDataURL(this.files[0]);
};
function previewImages() {
var $preview = $('#previewItemImages').empty();
if (this.files) $.each(this.files, readAndPreview);
function readAndPreview(i, file) {
var reader = new FileReader();
$(reader).on("load", function () {
$preview.append($("<img/>", {src: this.result, height: 100}));
});
reader.readAsDataURL(file);
}
}
$('#itemImages').on("change", previewImages);
I'm guessing that the conflict is between the html script and this
document.getElementById("frontImages").onchange = function ()
I also have a question how I can fix that there will be no small image when the image is too big
Your guess is correct, onchange is simply member variable of various elements, and thus
var uploadField = document.getElementById("frontImages");
uploadField.onchange = function() {
and
document.getElementById("frontImages").onchange = function ()
are setting this single variable (of frontImages), which will store one callback function at a time.
You could use addEventListener() instead, which maintains a list of event listeners, so there can be more than one. Modifying the lines to
var uploadField = document.getElementById("frontImages");
uploadField.addEventListener("change", function() {
and
document.getElementById("frontImages").addEventListener("change", function ()
will register both event listeners on frontImages, regardless of the order they are executed.
Side remark: when you have "nice" ids, document.getElementById() can be omitted, as elements with ids become variables (of window which is the global scope), and thus you could write frontImages.addEventListener(...). You still need the getter in various cases, like when a local variable shadows the id, or when it is not usable as variable identifier (like id="my-favourite-id" or id="Hello World")
Related
I'm currently trying create a drag and drop file uploader with the standard option to just use the regular input. I'm not sure what to be targeting to write if the user clicked the upload or dropped a file in.
My first thought was to check if the FileList is empty but both ways produce a FileList. Second thought was just write two functions one for the input and one for the drop but that seems like I would be repeating. Last thought was writing an if statement in the read_file function. However, I'm not sure what to target exactly.
Any ideas would be greatly appreciated!! thanks!!
https://jsfiddle.net/nick1572/b4xzt8oh/3/
var uploader = document.querySelector('.uploader');
var output = document.getElementById('output');
var file = document.getElementById('file');
file.addEventListener('change', function(event) {
read_file(event);
});
function read_file(event) {
file = event.target;
var reader = new FileReader();
reader.onload = function() {
var data_url = reader.result;
output.src = data_url;
};
// This will read when the image is dropped.
//reader.readAsDataURL(event.dataTransfer.files[0]);
reader.readAsDataURL(file.files[0]);
/*
Something like this
if () {
reader.readAsDataURL(file.files[0]);
} else if() {
reader.readAsDataURL(event.dataTransfer.files[0]);
}
*/
};
uploader.addEventListener('dragover', function(e) {
console.log('drag over');
e.preventDefault();
});
uploader.addEventListener('dragenter', function(e) {
console.log('drag enter');
e.preventDefault();
});
uploader.addEventListener('dragleave', function() {
console.log('drag leave');
});
uploader.addEventListener('drop', function(event) {
console.log('drop');
event.preventDefault();
read_file(event);
});
Check the type property of the event object to see which event has been used.
function read_file(event) {
file = event.target;
var reader = new FileReader();
reader.onload = function() {
var data_url = reader.result;
output.src = data_url;
};
if (event.type === 'change') {
reader.readAsDataURL(file.files[0]);
} else if(event.type === 'drop') {
reader.readAsDataURL(event.dataTransfer.files[0]);
}
};
I am trying to create a function that will recursively try to reload an image until it either is successful, or a maximum amount of attempts is reached. I have created this function, but it doesn't work (is it due to the fact that the reference to the image has changed?):
function reload (image, URL, maxAttempts)
{
image.onerror = image.onabort = null;
if (maxAttempts > 0)
{
var newImg = new Image ();
newImg.src = URL;
newImg.onerror = image.onabort = reload (image, URL, maxAttempts - 1);
newImg.onload = function () {
newImg.onerror = newImg.onabort = null;
image = newImg;
}
}
else
{
alert ("Error loading image " + URL); /* DEBUG */
}
}
Which is used in the following manner:
var globalTestImage = new Image ();
reload (globalTestImage, "testIMG.jpg", 4);
Rather than it attempting to load "testIMG.jpg" four times, and waiting in between attempts, it instead tries to load it twice, and regardless of whether it was successful the second time around it will display the error message.
What am I doing there? More precisely, why is it acting the way it is, rather than retrying to load the image 4 times?
(function ($) {
var retries = 5; //<--retries
$( document).ready(function(){
$('img').one('error', function() {
var $image = $(this);
$image.attr('alt', 'Still didn\'t load');
if (typeof $image !== 'undefined') {
if (typeof $image.attr('src') !== 'undefined') {
$image.attr('src', retryToLoadImage($image));
}
}
});
});
function retryToLoadImage($img) {
var $newImg = $('<img>');
var $src = ($img.attr('src')) || '';
$newImg.attr('src', $src);
$newImg.one('error', function() {
window.setTimeout(function(){
if (retries > 0) {
retries--;
retryToLoadImage($newImg);
}
}, 1000); //<-retry interval
});
$newImg.one('load', function() {
return $newImg.attr('src');
});
}
})(jQuery);
Some code I wrote for the same case a while ago. Hope it helps you!
In the end I solve this issue in a simple (if inelegant) way:
try
{
canvas.getContext("2d").drawImage (testImage, 0, 0);
backgroundLoaded = true;
}
catch (err)
{
testImage = new Image ();
testImage.src = "placeholder.jpg";
}
The idea is that if an image failed to load, it will fail when rendering it on the canvas, producing an error. When such an error happens, we can create a new image and try again.
I know that I should follow the DRY principle in coding. However, I am not that into javascript so I want to ask how to make the code below more readable and maintanable.
$('#frontfile_v').change(function(){
reader = Main.Mod.image_change(this);
reader.onload = frontvImageIsLoaded;
});
$('#rearfile_v').change(function(){
reader = Main.Mod.image_change(this);
reader.onload = rearvImageIsLoaded;
});
$('#rightfile_v').change(function(){
reader = Main.Mod.image_change(this);
reader.onload = rightvImageIsLoaded;
});
$('#leftfile_v').change(function(){
reader = Main.Mod.image_change(this);
reader.onload = leftvImageIsLoaded;
});
//called after an image file has been chosen
function frontvImageIsLoaded(e) {
$("#frontimagepreview").attr('src', e.target.result);
$("#frontpreview-msg").css('color', 'green');
};
function rearvImageIsLoaded(e) {
$("#rearimagepreview").attr('src', e.target.result);
$("#rearpreview-msg").css('color', 'green');
};
function rightvImageIsLoaded(e) {
$("#rightimagepreview").attr('src', e.target.result);
$("#rightpreview-msg").css('color', 'green');
};
function leftvImageIsLoaded(e) {
$("#leftimagepreview").attr('src', e.target.result);
$("#leftpreview-msg").css('color', 'green');
};
This is the code for Main.Mod.image_change()
var image_change = function handleFileImageChange(obj){
//holds the image preview object
var file = obj.files[0];
var imagefile = file.type;
var match= ["image/jpeg","image/png","image/jpg"];
if(!((imagefile==match[0]) || (imagefile==match[1]) || (imagefile==match[2]))){
alert("Incorrect image file. You still be able to upload this form but the system " +
"will be using the default image.");
$("#preview-msg").css('color', 'red');
return false;
}else{
var reader = new FileReader();
//reader.onload = imageIsLoaded;
reader.readAsDataURL(obj.files[0]);
return reader;
}
};
The code above, will handle file input change event then change img src base on the file input.
I know the code i wrote really sucks since I have to repeat my code several times. How can I implement it in a more efficient way?
Thanks.
use , to combine selectors:
$('#frontfile_v,#rearfile_v').change(function(){
// ...
})
The "change" event will be bound to every object matched by the selector. This way you don't need to duplicate the binding.
Merge the "image loaded" functions into one function by passing parameters:
var idsMap = {
leftfile_v : {preview : '#frontimagepreview', msg : '#frontpreview-msg'},
// etc...
};
$('#leftfile_v,#rearfile_v').change(function(){
var ids = idsMap[$(this).attr('id')];
reader = Main.Mod.image_change(this);
reader.onload = function(e) {
imageIsLoaded(e, ids.preview, ids.msg);
};
});
function imageIsLoaded(e, preview, msg) {
$(preview).attr('src', e.target.result);
$(msg).css('color', 'green');
};
Yet another variant. As say #Malki: use comma in selector
$('#frontfile_v, #rearfile_v,#rightfile_v,#leftfile_v').change(function(){
var id = this.id.replace(/file_v$/,'');
reader = Main.Mod.image_change(this);
if(reader){ //for case when `image_change` return not "false"
// use mode generic function
reader.onload = function(e){
$("#"+id+"imagepreview").attr('src', e.target.result);
$("#"+id+"preview-msg").css('color', 'green');
};
}
});
As for handleFileImageChange you need use Array.indexOf function
var image_change = function handleFileImageChange(obj){
//holds the image preview object
var file = obj.files[0];
var imagefile = file.type;
var match= ["image/jpeg","image/png","image/jpg"];
if(match.indexOf(imagefile) == -1){
alert("Incorrect image file. You still be able to upload this form but the system will be using the default image.");
$("#preview-msg").css('color', 'red');
return false;
}else{
var reader = new FileReader();
//reader.onload = imageIsLoaded;
reader.readAsDataURL(file); //you not need use "obj.files[0]" because you already save it in "var file"
return reader;
}
};
I have two functions in jQuery. One of them looks for image extensions from form and another is getting image dimensions and triggers an alert() when an image is not big enough.
Both functions are correctly executed in demos but together only one is executed. Only part where extensions is getting is executed. Sorry for the length of the code but it was the only way to show the problem.
(function ($) {
$.fn.checkFileType = function (options) {
var defaults = {
allowedExtensions: [],
success: function () {},
error: function () {}
};
options = $.extend(defaults, options);
return this.each(function () {
$(this).on('change', function () {
var value = $(this).val(),
file = value.toLowerCase(),
extension = file.substring(file.lastIndexOf('.') + 1);
if ($.inArray(extension, options.allowedExtensions) == -1) {
options.error();
$(this).focus();
} else {
options.success();
}
});
});
};
})(jQuery);
$("#filput").on('change', function () {
var fr = new FileReader;
fr.onload = function () { // file is loaded
var img = new Image;
img.onload = function () {
// image is loaded; sizes are available
var w = img.width
if (w < 500) {
alert("too small");
} else {
alert("big enough");
}
};
img.src = fr.result;
};
fr.readAsDataURL(this.files[0]);
});
$(function () {
$('#filput').checkFileType({
allowedExtensions: ['jpg', 'jpeg', 'png'],
error: function () {
alert('error');
}
});
});
Only part where extentions is getting is executed
That code is wrapped by $(function() { ... }); so, you should probably put both pieces of code there:
$(function() {
$("#filput").on('change', function () {
var fr = new FileReader;
// ...
});
$('#filput').checkFileType({
// ...
});
});
Based on what you have described, the input element wasn't present yet at the time your code is run; by putting both code segments in the DOMReady event handler, you're making sure it exists.
I'm having an issue with getting the dimensions of a newly updated image element.
I'm using FileReader to display a preview of an image file on screen.
Once the filereader and associated code has finished executing, I retrieve the new dimensions of the image element so I can adjust them accordingly.
On some browsers, the info doesn't get updated straight away and I need to include a delay before I can retrieve the new dimensions. This results in the new image being resized according to the previous image's dimensions, and not its own.
How can I be sure the new image has been fully loaded?
I would have thought FileReader().onloadend would have been sufficient but apparently not. I think this is executed once the fileReader has loaded it, not when the DOM has rendered it. (Am I right?)
Then I found this question, which suggests using a timeout of 1 millisecond. This works sometimes, but not always. It seems to be down to the speed the browser is rendering the image (more-so available resources rather than filesize). Do we have no other way of detecting a change in these parameters?
HTML
<img src="#.png" alt=""/>
<input id="fileInput" type="file" accept='image/*' onChange="loadIt()" />
JS
preview = getElementsByTagName('img')[0];
function loadIt() {
var imgReader = new FileReader();
imgReader.readAsDataURL(document.getElementById('fileInput').files[0]); //read from file input
imgReader.onloadstart = function(e) {
//
}
imgReader.onload = function (imgReaderEvent) {
if (isImage()) {
preview.src = imgReaderEvent.target.result;
//
}
else {
preview.src = 'error.png';
//
}
}
imgReader.onloadend = function(e) {
setImage();
setTimeout(function(){
setImage();
}, 1);
setTimeout(function(){
setImage();
}, 2000);
//
}
};
function setImage() {
preview_w = preview.width;
preview_h = preview.height;
console.log('dimensions: '+avatar_preview_w+' x '+avatar_preview_h);
//
};
You should call preview.onload or preview.onloadend on your image to detect that it has finished loading. You're also calling your events after you readAsDataURL The code should look like this
var preview=document.getElementsByTagName("img")[0];
function loadIt() {
var imgReader=new FileReader();
imgReader.onload=function(){
if (isImage()) {
preview.src = imgReader.result;
preview.onload=setImage;
} else {
preview.src = 'error.png';
//
}
imgReader.readAsDataURL(document.getElementById('fileInput').files[0]); //read from file input
}
function setImage(){
preview_w = preview.width;
preview_h = preview.height;
console.log('dimensions: '+avatar_preview_w+' x '+avatar_preview_h);
}
You're calling imgReader.readAsDataURL before your .onload and .onloadend is set.
I do not know what some of the variables are with-in the body of your setImage();however, start here:
function loadIt() {
var preview = getElementsByTagName('img')[0],
setImage = function () {
preview_w = preview.width;
preview_h = preview.height;
console.log('dimensions: '+avatar_preview_w+' x '+avatar_preview_h);
},
imgReader = new FileReader();
imgReader.onloadstart = function(e) {};
imgReader.onload = function (imgReaderEvent) {
if (isImage()) {
preview.src = imgReaderEvent.target.result;
}
else {
preview.src = 'error.png';
};
};
imgReader.onloadend = function(e) {setImage();};
imgReader.readAsDataURL(document.getElementById('fileInput').files[0]); //read from file input
};