Simplifiying/modularizing my code in javascript - javascript

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;
}
};

Related

Detect if file upload was from drag or regular input click

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]);
}
};

Javascript file in conflict with other javascript

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")

How can I simulate $(this)[0].files in JS?

I have a drag and drop container for uploading images. Something like the option that stackoverflow has in the editor. As you know, it works in two ways:
drag and drop an image
click on the container and then a window will be opened to choose an image
Now I'm exactly doing something like that:
// click
$('.upload_image').on('change', function () {
file = $(this)[0].files;
frm = $(this).closest('form');
addImageToInput();
return false;
});
// drag and drop
$(".container").on('drop dragdrop', function (e) {
file = e.originalEvent.dataTransfer.files;
frm = $(this).closest('form');
addImageToInput();
return false;
});
Also I have one more function for making a preview:
function addImageToInput() {
if ( file !== "" || frm !== "" ) {
let uploadFormData = new FormData(frm[0]);
uploadFormData.append("imageToUpload", file[0]);
readURL(frm.find(".upload_image")[0]);
formData = uploadFormData;
} else {
alert('something went wrong');
}
}
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
$('.modal-dropzone-img').html("<img src='" + e.target.result + "' class='upload_image_preview_img'/>");
}
reader.readAsDataURL(input.files[0]);
}
}
Anyway, the preview part works well when I attach an image by using "click" (browse) the image, and the preview part doesn't word (even no error throws) when I use drag and drop approach.
After some tests, I figured out, these aren't equal:
file = $(this)[0].files; // click approach
file = e.originalEvent.dataTransfer.files; // drag and drop approach
Any idea how can I make them equal? (in other word, I have to make the second one like the first one, because the first one is the working one)
I have modified the readURL method little bit to accept a file only, it can be drag drop or uploaded . Also addImageToInput() is changed accordingly
function addImageToInput() {
if ( file !== "" || frm !== "" ) {
let uploadFormData = new FormData(frm[0]);
uploadFormData.append("imageToUpload", file[0]);
readURL(file[0]);
formData = uploadFormData;
} else {
alert('something went wrong');
}
}
function readURL(input) {
if (input) {
var reader = new FileReader();
reader.onload = function(e) {
$('.modal-dropzone-img').html("<img src='" + e.target.result + "' class='upload_image_preview_img'/>");
}
reader.readAsDataURL(input);
}
}
here is a working fiddle
https://jsfiddle.net/153dp05q/

Upload from desktop with HTML5 and Javascript (drag and drop)

I'm making a typical drag and drop for upload images from desktop to browser, i can drop content inside the box and with a console.log view the content in the browser console:
File { name: "deam230mthumb.jpg", lastModified: 1194641808000, lastModifiedDate: Date 2007-11-09T20:56:48.000Z, size: 60313, type: "image/jpeg" }
I want to view the image inside a box and then upload on submit.
Here my code is use Jade template engine:
Jade (HTML)
form(action="" enctype="multipart/form-data")
div(class="all-100 miniatures")
div(class="all-100 drop ink-droppable align-center fallback" id="dropZone" ondrop="drop(event)" ondragover="allowDrop(event)")
Javascript
script.
var dropZone = document.getElementById('dropZone');
function allowDrop(e){
e.preventDefault();
}
function drop(e){
var file = e.dataTransfer.files[0];
e.preventDefault();
console.log(file);
//e.target.appendChild(file);
}
I added an array for content each file from the event, on the following code we need to add a controller for handle each file from the array with a register of each one on the database.
script.
var dropZone = document.getElementById('dropZone');
function allowDrop(e){
e.preventDefault();
}
var files = [];
function drop(e){
var file = e.dataTransfer.files[0];
files.push(file);
console.log(file)
e.preventDefault();
var reader = new FileReader();
reader.onload = function(event){
var miniatures = document.getElementById("miniatures");
var img = new Image();
img.src = event.target.result;
var miniature = document.createElement("div");
miniature.className = "all-20";
miniature.appendChild(img);
miniatures.appendChild(miniature);
}
var readerContent = reader.readAsDataURL(file);
var input = document.getElementById("upload");
input.files = readerContent;
console.log(files);
}
Ok, my Javascript looks this now:
At this point we can drag images from our desktop to browser and view
them, now, we need to upload that files.
script.
var dropZone = document.getElementById('dropZone');
function allowDrop(e){
e.preventDefault();
}
function drop(e){
var file = e.dataTransfer.files[0];
e.preventDefault();
console.log(file);
var reader = new FileReader();
reader.onload = function(event){
var miniatures = document.getElementById('miniatures');
var miniature = new Image();
miniature.src = event.target.result;
miniature.width = 100;
miniatures.appendChild(miniature);
}
reader.readAsDataURL(file);
}

drag file to browser from local

I want drop jpg to Browser from local, and display it on Browser.
I write code, but it don't display jpg.
Please advice.
html
<img id="img1" ondragover="doDragOver(event);"
ondrop="doDrop(event);"
class="droppable">
css
.droppable {
width:500px;
height:500px;
background-color: gray;
}
script
function doDragOver(event){
var type = event.dataTransfer.types.contains("Files");
if (type){
event.preventDefault();
}
}
function doDrop(event){
var img = document.getElementById("img1");
var file = event.dataTransfer.files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function() {
img.src = reader.result;
}
}
The problem is that the dragOver function the type list is empty (to it's empty in some browsers), but why check it content? You can check it in the drop function.
Be sure to cancel the default browser behavior using event.preventDefault(); and return false
Code:
function doDragOver(event) {
event.preventDefault();
return false
}
function doDrop(event) {
event.preventDefault();
var img = document.getElementById("img1");
var file = event.dataTransfer.files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
img.src = reader.result;
}
}
Demo: http://jsfiddle.net/IrvinDominin/Up2NF/

Categories