Use label to select image file but have attribute displayed input - javascript

I am looking to have the label be used for the selection of the item (so Choose File) is gone.
Here is my HTMl:
<div class="form-group">
<label class="btn btn-primary trigger" for="broker_image">Upload Image</label>
<input style="display:none;" class="uploadBtn" type="file" name="broker[image]" id="broker_image">
</div>
It works, although I do not have the image to actually have the name shown (which is part of the input tag)
Here is the js to try to make it show (which is 100% editable):
document.getElementsByClassName("trigger").onClick = function () {
document.getElementsByClassName("uploadFile").style.display = 'block';
document.getElementsByClassName("uploadFile").value = this.value;
};
Tried:
document.getElementsByClassName("trigger").onClick = function () {
document.getElementsByClassName("uploadFile")[0].style.display = 'block';
document.getElementsByClassName("uploadFile")[0].value = this.value;
};
With no luck.
JSFiddle:
http://jsfiddle.net/07zw6h3q/
I am lost on to make just the file name show, without some crazy javascript add in. Something simple. Using Rails 4.2 and Bootstrap.

You need to use the change event.
$('.uploadBtn').change(function(){
var a = $(this).val().split('\\');
$('.trigger').html(a[a.length - 1]);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="form-group">
<label class="btn btn-primary trigger" for="broker_image">Upload Image</label>
<input style="display:none;" class="uploadBtn" type="file" name="broker[image]" id="broker_image">
</div>
Also you can show a preview of the file (if it's image of course) Preview an image before it is uploaded

JSFiddle
HTML
<div class="form-group">
<label class="btn btn-primary trigger" for="broker_image" style="border : solid 1px lightgrey; padding : 5px">Upload Image</label>
<input style="display:none"; class="uploadBtn" type="file" name="broker[image]" id="broker_image" />
<label id="broker_image_name">no selected file</label>
</div>
JavaScript
var upload_button = document.getElementById("broker_image");
upload_button.addEventListener("change", function() {
var file_name = upload_button.value;
/*
the file come like this : C:\fakepath\file.htm
so we only need the file name
*/
file_name = file_name.split("\\"); // preventing \ to be escaped himself
var file_name_length = file_name.length;
file_name = file_name[file_name_length - 1];
var broker_image_name = document.getElementById("broker_image_name");
broker_image_name.innerHTML = file_name;
});
I used the event change to change the file name, which is an additional label I put right after your button (that I stylized a bit by the way) and that is updated with the file name.
You see a commented part for the file name value because when getting back the file name after the user select one, it comes with the pattern C:\fakepath\myFile.htm so I extracted only the file by splitting the string.

Related

Detect input click with dynamic id using JQuery

In the website is the ability to ask a question and provide answers with images. We have used some website template and now trying to change functionallity. So I'm trying to achieve if image clicked, pop ups upload window (to select picture) and after clicking ok button, it should be shown near the answer (look image below, noted in red).
There is the ability to add more input fields by clicking the button. It generating HTML like this:
<div class="row">
<div class="another-div">
<div class="image-answer">
<input type="image" name="answers_images[]" id="test-1" src="image.png">
<input type="file" name="answers_images[]" id="file-1" style="display: none;">
</div>
<label class="text-answer">
<input type="text" name="answers[]" placeholder="Type here your answer">
</label>
</div>
</div>
If user clicks the button it will add another row with incremented ids, so it will be test-2, file-2
after clicking button once again it will add row with incremented ids once again test-3, file-3 and so on.
How can I detect input clicks (via JQuery) if ids are auto incremental? And after it do some changes with JQuery only with clicked ($this) image.
Something like this:
$("#file-1...").click(function(e) {
e.preventDefault();
// Some code here, I have working code to achieve what I want
// But problem, that I have no idea how to detect those clicks with dynamic ids
});
$("#test-1").change(function(e) {
e.preventDefault();
});
If you want to do event handling on dynamically added content, the trick is using the .on() method with a non-dynamically added parent element, and providing a selector argument. This approach use classes instead of ids. You cans still have ids, but the this variable becomes the element selected, so you don't really need them.
<div class="parent">
<div class="image-answer dynamically-added" id="answer1"></div>
<div class="image-answer dynamically-added" id="answer2"></div>
<div class="image-answer dynamically-added" id="answer3"></div>
</div>
$('.parent').on('click', '.image-answer', function() {});
Say if you clicked on the second .image-answer, in the event handler function this would be the same as $('#answer2')[0]. So to make it a jquery object you just have to $(this). And if you want to access a child elemet, just use the .find() method.
$(this).find('input[type="file"]').on('change', function previewFile() { ... })
Also, inputs dont' have a default action for click, so e.preventDefault() isn't necessary.
You can use class selector instead of id's to have a more dynamic approach of what you are trying to achieve. Also with class you will be writing less code and getting the same results.
You can still use the id's increment system to make sure the id's are unique in the DOM.
Add class to your input image and input file and and watch a change on those classes. You can use prev() method you select the previous input of which the change was made on using $(this)
//Load preview image on each answer
$(document).on('click', '.add_image', function(e) {
e.preventDefault()
//add file to input / trigger click
$(this).next('input').click();
})
//Watch the change on select file
$(document).on('change', '.select_file', function(e) {
e.preventDefault()
//get the sibling img src of the change file
var prevInput = $(this).prev('input')
//Call read file preview
previewFile(this, prevInput);
});
Pass your input and prev input image where the change happened to your previewImage function so that the file can be previewed in the image location using file Reader API.
//Preview img
function previewFile(input , previewSrc) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
//load file into actual preview img
$(previewSrc).attr('src', e.target.result);
}
reader.readAsDataURL(input.files[0]); // convert to base64 string
}
}
I have added the functionality of adding more answers as well and you can upload image and preview images on those new answers as well using event Delegation as the elements are being append dynamically.
Complete Working Demo:
//row with incremented ids
var counter = 2
//Add more
$('#add_more').click(function() {
//add new answer
var newRow = `<div class="another-div">
<div class="image-answer">
<input type="image" class='add_image' name="answers_images[]" id="test-` + counter + `" src="https://img.icons8.com/dotty/80/000000/upload.png">
<input type="file" class='select_file' name="answers_images[]" id="file-` + counter + `" style="display: none;">
</div>
<label class="text-answer">
<input type="text" name="answers[]" id="answer-` + counter + `" placeholder="Type here your answer">
</label>
<button class="remove_answer"><i class="fas fa-window-close"></i></button>
</div>`
//append new answers
$('.row').append(newRow)
counter++ //increare counter
})
//remove answer
$(document).on('click', '.remove_answer', function() {
//remove the answer div
$(this).parent().remove()
counter-- //decrease counter
})
//Load preview image on each answer
$(document).on('click', '.add_image', function(e) {
e.preventDefault()
//add file to input / trigger click
$(this).next('input').click();
})
//Watch the change on select file
$(document).on('change', '.select_file', function(e) {
e.preventDefault()
//get the sibling img src of the change file
var prevInput = $(this).prev('input')
//Call read file preview
previewFile(this, prevInput);
});
//Preview img
function previewFile(input, previewSrc) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
//load file into actual preview img
$(previewSrc).attr('src', e.target.result);
}
reader.readAsDataURL(input.files[0]); // convert to base64 string
}
}
.add_image {
width: 80px;
height: 80px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://kit.fontawesome.com/a076d05399.js"></script>
<div class="row">
<div class="another-div">
<div class="image-answer">
<input type="image" class='add_image' name="answers_images[]" id="test-1" src="https://img.icons8.com/dotty/80/000000/upload.png">
<input type="file" class="select_file" name="answers_images[]" id="file-1" style="display: none;">
</div>
<div id="preview_img"></div>
<label class="text-answer">
<input type="text" name="answers[]" id="answer-1" placeholder="Type here your answer">
</label>
</div>
</div>
<br>
<button id="add_more">
Add New Answer
</button>

How to validate an image file in a form using spry or any other tweak

I have a form that checks 4 parameters, the first three are easy to check with spry and working fine. But the fourth is an upload of an image, i want to check if the extension of the file is correct or not. But there is not an option that i see that does that. How is it possible to check the extension of the file uploaded?
What i've done:
I had in an older version (only implemented a file upload and submit button) is a script that worked based on using ID, that detected the click on a sending buttong and then check the file description. When i simply link the script to the current form it does not work, also i want the same behaviour as the other form inputs with the hidden message, not with alert as it is in the code.
To put the file i copied a spry text validation and changed the input type to file.
EDIT: It wasn't clear enought so i wanna make an aclaration, i want to validate the input files. Dont want the user to be able to upload anything that is not allowed in the list of extensions allowed.
Here is the part of the HTML that defines the form i use, also both methos used to do it (only used once at a time, but easy to show like this).
<form action="../Data/Product.Insert.php" method="post" enctype="multipart/form-data" name="Insert">
<span id="sprytextfield1">
<label for="Name">Name</label>
<input type="text" name="Name" id="Name" tabindex="1">
<span class="textfieldRequiredMsg">A value is required.</span> <br>
</span> <span id="sprytextfield2">
<label for="Ref">Ref</label>
<input type="text" name="Ref" id="Ref" tabindex="2">
<span class="textfieldRequiredMsg">A value is required.</span></span> <br>
<span id="spryselect1">
<label for="Cat">Cat</label>
<select name="Cat" id="Cat" tabindex="3">
<option value="test">test</option>
</select>
<span class="selectRequiredMsg">Please select an item.</span></span> <br>
<span id="sprytextfield3">
<label for="Image">Image</label>
<input type="file" name="Image" id="Image" tabindex="4" id="image">
<span class="textfieldRequiredMsg">A value is required.</span></span><br>
<input name="Send" type="submit" value="Send" tabindex="5" id="insert">
</form>
<script type="text/javascript">
var sprytextfield1 = new Spry.Widget.ValidationTextField("sprytextfield1", "none");
var sprytextfield2 = new Spry.Widget.ValidationTextField("sprytextfield2");
var spryselect1 = new Spry.Widget.ValidationSelect("spryselect1");
var spryselect1 = new Spry.Widget.ValidationSelect("sprytextfield3","image");
$(document).ready(function(){
$('#insert').click(function(){
var image_name = $('#image').val();
if(image_name == '')
{
alert("Please Select Image");
return false;
}
else
{
var extension = $('#image').val().split('.').pop().toLowerCase();
if(jQuery.inArray(extension, ['gif','png','jpg','jpeg']) == -1)
{
alert('Invalid Image File');
$('#image').val('');
return false;
}
}
});
});
</script>
Here is my failure to convert that code into a validation type in a spry, this only makes the whole form not to work.
'image'{
validation: function(value, options) {
if(value = ""){
return false;
}
var extension = $('#image').val().split('.').pop().toLowerCase();
if(jQuery.inArray(extension, ['gif','png','jpg','jpeg']) == -1)
{
return false;
}
return true;
}
},
you can use accept="image/*" attribute to validate images
Thanks
Here is one example using the file reader api. hope this helps
Regards
$('.UploadImage').change(function (ev) { // this triggers when file upload is clicked
.readImage(this);
});
public readImage(input) {
let reader = new FileReader();
let imageName = input.files[0].name.split(".").slice(0, -1).join(".").replace(/[^A-Z0-9]+/ig, "");
let MIMEType = input.files[0].type;
// Do validation stuff here based on the mime type
reader.onload = function () {
el.attr('src', reader.result);
console.log(reader.result);
}
reader.readAsDataURL(input.files[0]);
}

Previewing multiple uploaded images individually

I have three image upload fields in my form. I am trying to preview the images before uploading. Till now i have been able to preview only one at a time. but i am trying to preview all of them simultaneously. Like
I am currently previewing like this.
function previewImages() {
var $preview = $('#preview').empty();
if (this.files) $.each(this.files, readAndPreview);
function readAndPreview(i, file) {
if (!/\.(jpe?g|png|gif)$/i.test(file.name)){
return alert(file.name +" is not an image");
} // else...
var reader = new FileReader();
$(reader).on("load", function() {
$preview.append($("<img/>", {src:this.result, height:500}));
});
reader.readAsDataURL(file);
}
}
$('#file-input').on("change", previewImages);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="form-group">
<label>Image 2</label>
<input id="file-input" type="file" multiple>
<div id="preview"></div>
</div>
<img id='img-upload'/>
</div>
<div class="form-group">
<label>Image 3</label>
<input id="file-input" type="file" multiple>
<div id="preview"></div>
</div>
You have some problems in your code.
Never use duplicate id's . That's the main reason your code works only for the first input type file. You use id='file-input' on all inputs. That's not correct HTML wise. Use classes instead or other html attributes.
You select the preview container but only the first one. $preview = $('#preview').empty(); where by writing $('#preview'), jquery finds the first item with id preview, selects it, empties it and then ignores all other divs with the same id. This is firstly because you don't select the corresponding preview div to the changed input file ( no connection between them in your var declaration ) and because again you use duplicate ( multiple ) id's in your HTML structure. Which will generate a lot of ' strange ' errors.
But even if you would use classes instead of id's ( class='preview' ) it won't exactly work because it will just select the first div with class preview and append all previews to that div.
So to make a connection between input and it's preview, use something like var $preview = $(this).next('.preview').empty(); . This way you know jQuery will select the next sibling with class preview of the changed input.
Alternatively ( if your HTML structure should change and preview is not exactly after the input ) you should use $(this).siblings('.preview').empty()
The most important thing you should learn from this answer is NOT to use same id`s on the page. And when you have multiple items with corresponding elements, select them accordingly.
function previewImages() {
const $preview = $(this).next('.preview').empty();
if (this.files) $.each(this.files, readAndPreview);
function readAndPreview(i, file) {
if (!/\.(jpe?g|png|gif)$/i.test(file.name)) {
return alert(file.name + " is not an image");
} // else...
const reader = new FileReader();
$(reader).on("load", function() {
$preview.append($("<img/>", {
src: this.result,
height: 100
}));
});
reader.readAsDataURL(file);
}
}
$('.file-input').on("change", previewImages);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="form-group">
<label>Image 1</label>
<input class="file-input" type="file" multiple>
<div class="preview"></div>
</div>
<img class='img-upload' />
<div class="form-group">
<label>Image 2</label>
<input class="file-input" type="file" multiple>
<div class="preview"></div>
</div>
<img class='img-upload' />
<div class="form-group">
<label>Image 3</label>
<input class="file-input" type="file" multiple>
<div class="preview"></div>
</div>
SIDE NOTE . You should use const and/or let instead of var when declaring variables.
var $preview=null;
function previewImages() {
$preview = $(this).next('#preview').empty();
if (this.files)
$.each(this.files,function(index,file){
readAndPreview(index,file);
});
}
function readAndPreview(i, file) {
if (!/\.(jpe?g|png|gif)$/i.test(file.name)){
return alert(file.name +" is not an image");
} // else...
var reader = new FileReader();
$(reader).on("load", function() {
$preview.append($("<img/>", {src:this.result, height:100}));
});
reader.readAsDataURL(file);
}
$('.file-input').on("change", previewImages);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="form-group">
<label>Image 2</label>
<input class="file-input" type="file" multiple>
<div id="preview"></div>
</div>
<img id='img-upload'/>
</div>
<div class="form-group">
<label>Image 3</label>
<input class="file-input" type="file" multiple>
<div id="preview"></div>
</div>
Try this. css ids are unique for a page. if you want to access multiple elements with same selector use class.

adding input file tag programmatically using js

I want to add input (type file) field to my html using js. I've got it done, but the problem is when the user chooses a file then clicks on the "new file" button to choose another one, The prevoius choosen file goes away and says no file chosen. what is the problem?
function newfile(){
var divv=document.getElementById("files");
var name="files"+divv.childNodes.length;
divv.innerHTML+='<div><input id="'+name+'" name="'+name+'" type="file" accept="*" class="col-lg-11 col-md-10 col-sm-10 col-sx-6"></div>';
}
<div class="col-sm-10">
<div id="files"></div>
<a class="btn btn-primary col-sx-12" onclick="newfile()">New file</a>
</div>
This happens because everytime you use divv.innerHTML+='<div><input id="'+name+'" name="'+name+'" type="file" accept="*" class="col-lg-11 col-md-10 col-sm-10 col-sx-6"></div>' all contents in divv are replaced with new contents and the previous information is lost.
you can use appendChild() here, something like this:
function newfile(){
var divv=document.getElementById("files");
var name="files"+divv.childNodes.length;
var inputNode = document.createElement("input");
inputNode.id = name;
inputNode.name = name;
inputNode.type = 'file';
divv.appendChild(inputNode);
}
<div class="col-sm-10">
<div id="files"></div>
<a class="btn btn-primary col-sx-12" onclick="newfile()">New file</a>
</div>

jQuery autocomplete for innerHTML generated textbox

I realize similar questions have been asked thousands times and yet it doesn't seem to work for me. I have a textbox called "movieTitle", it is generated via Javascript by clicking a button. And I'm calling jQueryUI autocomplete on that textbox just like in the official example http://jqueryui.com/autocomplete/#remote.
It works well if I hardcode "movieTitle" in the original page; however it just fails when I create "movieTitle" by changing the innerHTML of the div "formsArea". searchMovies.php is the same with search.php from the example. I had tried many answers from internet and from here. I learned that I would have to use .on() to bind the dynamic element "movieTitle". Still it doesn't seem to work. Even the alert("hahaha") works. Thanks for your time. :) Here's my script:
$(function()
{
$(document).on('focus', '#movieTitle', function(){
//alert("hahaha");
$("#movieTitle").autocomplete({
source: "../searchMovies.php",
minLength: 2
});
}
);
window.onload = main;
function main()
{
document.getElementById("movieQuery").onclick = function(){showForms(this.value);};
document.getElementById("oscarQuery").onclick = function(){showForms(this.value);};
// displays query forms based on user choice of radio buttons
function showForms(str)
{
var heredoc = "";
if (str === "movie")
{
heredoc = '\
<h1>Movie Query</h1>\
<form action="processQuery.php" method="get">\
<div class="ui-widget">\
<label for="movieTitle"><strong>Name: </strong></label>\
<input type="text" id="movieTitle" name="movieTitle" />\
<input type="submit" name="submitMovie" value="Submit" />\
</div>\
</form>';
//document.getElementById("formsArea").innerHTML = heredoc;
//$("#formsArea").append(heredoc);
$("#formsArea").html(heredoc);
}
else if (str === "oscar")
{
heredoc = '\
<h1>Oscar Query</h1>\
<form action="processQuery.php" method="get">\
<strong>Name: </strong>\
<input type="text" name="oscarTitle" />\
<input type="submit" name="submitOscar" value="Submit"/>\
</form>';
document.getElementById("formsArea").innerHTML = heredoc;
}
}
}
});
The HTML is:
<form action=$scriptName method="get">
<label for="movieQuery"><input type="radio" name="query" id="movieQuery" value="movie" />Movie Query</label>
<label for="oscarQuery"><input type="radio" name="query" id="oscarQuery" value="oscar" />Oscar Query</label>
</form>
<div id="formsArea">
<b>Please choose a query.</b>
</div>
You should check for the URL you're sending an AJAX request to. The paths in script files are relative to the page they're being displayed in. So albeit your script is in /web/scripts/javascripts/js.js, when this file is included in /web/scripts/page.php, the path to /web/scripts/searchMovies.php should be searchMovies.php instead of ../searchMovies.php because your script is being used in /web/scripts/.
Good ways to avoid such confusion is to
a. use absolute URL
b. the URL that're relative to root of your domain (that start with a /),
c. or define your domain's path in a variable, var domain_path = 'http://www.mysite.com/' and use it in your scripts.
I hope it clarifies things :)
Relative Paths in Javascript in an external file

Categories