Hide image preview on input click/change - javascript

I have created a image preview in JavaScript with some script i found here, I'm new to JS and now I am trying to replace the content instead of appending it. Here is the code
I've tried to put empty(), replaceWith(), remove(), just before appendTo() like other similar questions on SO, I've tried to create a function to hide the div, and nothing seems to work. I was wondering if anyone would know why these functions doesn't work, Am i doing something wrong?
//my html/php
echo '<input required type="file" name="filesToUpload[]" multiple
id="image_upload" accept=".jpg, .jpeg">';
echo '<div id="gallery-preview" class="gallery-preview"></div>';
//javascript
$(function() {
var imagesPreview = function(input, placeToInsertImagePreview) {
if (input.files) {
var filesAmount = input.files.length;
for (i = 0; i < filesAmount; i++) {
var reader = new FileReader();
reader.onload = function(event) {
$($.parseHTML('<img style="width:150px; height:75px; margin-left:2px; margin-right:2px; border:1px solid black; padding:2px;">')).attr('src', event.target.result).appendTo(placeToInsertImagePreview);
}
reader.readAsDataURL(input.files[i]);
}
}
};
$('#image_upload').on('change', function() {
imagesPreview(this, 'div.gallery-preview');
});
});
When i create a function to hide() the div gallery-preview, the preview doesn't work anymore. Same for other functions mentioned above

I think you are trying to set it empty each time you run the function.
Modify the change function in your code to the following
$('#image_upload').on('change', function() {
//this line will set the contents to empty before you run your function
$('div.gallery-preview').html('');
//now call your function
imagesPreview(this, 'div.gallery-preview');
});

Related

How can I count appended elements and calculate their style?

I'm trying to create a local static page with an image uploader and a preview gallery to which append images while the user selects them. To be more specific, the image uploader is an <input type="file" multiple="multiple"> and whenever a user selects an image I have a <div class="preview__gallery"></div> to which I append the selected images from the File Explorer.
Here comes the problem. After the <img> tags are being attached to the gallery div I'd like to count them using jQuery .length property so I can then apply some custom style using .css() based on the counting results.
Seems like I can not target those images by class. I've read all across the internet and even here on SO for similar anwers and in fact I've already tried a lot of options. I've tried to use jQuery deferred functions with $.when(firstFunction()).done(otherFunction()), I've tried to use MutationObserver to control changes that occurs on the gallery div and I've also tried event delegation but without success because I don't have any event that triggers the function. It just have to start after the images are appended.
I'm currently calling the counting function as a callback after the function that appends the images. I put a console.log('before') on the first function and a console.log('after') on the counting one, and it seems that the callback is working correctly. However, the .length property is not working and this is because jQuery is not being able to target the image element on the DOM. In fact, using a console.log($('.preview__thumb')) outputs an empty jQuery object.
Here's the HTML:
<div class="concorso__body">
<div class="container">
<div class="row">
<div class="col-lg-8">
<div class="single__upload">
<div class="upload__field">
<input type="file" accept="image/*" multiple="multiple" class="drag__area" id="file__input">
<div class="upload__text">
<i class="bi bi-plus"></i>
<span>Trascina o clicca per caricare immagini</span>
</div>
</div>
<div class="preview__gallery" id="the__gallery"></div>
</div>
</div>
<div class="col-lg-4"></div>
</div>
</div>
</div>
And here's the JS (using jQuery):
$(document).ready(function() {
$(function() {
function imagesPreview(input, placeToInsertImagePreview, callback) {
if (input.files) {
var filesAmount = input.files.length;
for (i = 0; i < filesAmount; i++) {
var reader = new FileReader();
reader.onload = function(event) {
$($.parseHTML('<img class="preview__thumbs">')).attr('src', event.target.result).appendTo(placeToInsertImagePreview);
};
reader.readAsDataURL(input.files[i]);
console.log('before');
}
if(typeof callback === 'function') {
callback();
}
}
}
});
});
$(document).ready(function() {
$(function() {
function imagesPreview(input, placeToInsertImagePreview, callback) {
if (input.files) {
var filesAmount = input.files.length;
var count = 0; // Initialize a counter for the number of images
for (i = 0; i < filesAmount; i++) {
var reader = new FileReader();
reader.onload = function(event) {
$($.parseHTML('<img class="preview__thumb">')).attr('src', event.target.result).appendTo(placeToInsertImagePreview);
count++; // Increment the counter after each image is added
if (count == filesAmount) { // Check if all images have been added
if (typeof callback === 'function') {
callback();
}
}
};
reader.readAsDataURL(input.files[i]);
}
}
}
// Call the imagesPreview function on file input change event
$('#file__input').on('change', function() {
var gallery = $('.preview__gallery');
imagesPreview(this, gallery, function() {
// This function is called after all images have been appended
var numImages = $('.preview__thumb').length;
console.log(numImages); // This should output the correct number of images
if (numImages > 5) {
gallery.css('background-color', 'red'); // Apply custom style if more than 5 images
}
});
});
});
});

View and Hide Image Using Jquery

I am displaying images before upload using jquery, when i upload some new files i want to remove or hide the previous upload files here's my jquery code:
$(function()
{
// Multiple images preview in browser
var imagesPreview = function(input, placeToInsertImagePreview)
{
if (input.files)
{
var filesAmount = input.files.length;
for (i = 0; i < filesAmount; i++)
{
var reader = new FileReader();
reader.onload = function(event)
{
$($.parseHTML('<img class="p-3" width="350px" height="250px">')).attr('src', event.target.result).appendTo(placeToInsertImagePreview);
}
reader.readAsDataURL(input.files[i]);
}
}
}
$('#file_input').on('change', function()
{
imagesPreview(this, 'div#viewUploadItems');
});
});
And my HTML Code:
<input type="file" name="images[]" id="file_input" class="deletable" multiple />
<div id="viewUploadItems"></div>
I try this code but this won't display any image.
$("#file_input").on("click",function()
{
$('input.deletable').val('');
$('#viewUploadItems').remove();
});
Perhaps you could take the following approach, where in your imagePreview() function you:
first call empty() on the preview selector to clear any prior image contents
then proceed to read and display any selected images, by using the FileReader API as you currently are (see below for revised approach)
Also, consider checking the type of the file object, to ensure that it is an image before attempting to display it via the following:
if (file.type.match("image.*")) {
/* file is image type, so attempt to preview it */
}
Bringing these ideas together, you could revise your code as follows:
$(function() {
function imagesPreview(input, targetSelector) {
/* Empty the target area where previews are shown */
$(targetSelector).empty();
/* Iterate each file via forEach in own closure */
Array.from(input.files).forEach(function(file) {
/* If file is image type proceed to preview */
if (file.type.match("image.*")) {
/* Create filereader and set it up for reading */
var reader = new FileReader();
reader.onload = function(event) {
/* Append a new image element, prepopulated with
required attrbutes, and assigned with p-3 class */
$(targetSelector).append($('<img>', {
width: '350px',
height: '250px',
src : reader.result
}).addClass('p-3'))
}
reader.readAsDataURL(file);
}
})
}
$('#file_input').on('change', function() {
imagesPreview(this, 'div#viewUploadItems');
});
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<input type="file" name="images[]" id="file_input" class="deletable" multiple />
<div id="viewUploadItems"></div>
Easier to clear the div before display : $(placeToInsertImagePreview).html("");
$(function()
{
// Multiple images preview in browser
var imagesPreview = function(input, placeToInsertImagePreview)
{
if (input.files)
{
$(placeToInsertImagePreview).html("");
var filesAmount = input.files.length;
for (i = 0; i < filesAmount; i++)
{
var reader = new FileReader();
reader.onload = function(event)
{
$($.parseHTML('<img class="p-3" width="350px" height="250px">')).attr('src', event.target.result).appendTo(placeToInsertImagePreview);
}
reader.readAsDataURL(input.files[i]);
}
}
}
$('#file_input').on('change', function()
{
imagesPreview(this, 'div#viewUploadItems');
});
});

Pure JS detect click on wrapper and focus on inner input

I have responsive design, with padded container around input. Problem is, when user clicks in padded area, input wont be focused.
In jQuery the working code is:
$('.wrap').on('click', function (e) {
$(this).find('input').focus();
});
But can't seem to get it working in JS:
var elm_rows = document.getElementsByClassName("wrap");
elm_rows.addEventListener("click", function (e) {
e.getElementsByTagName("input").focus();
});
https://jsfiddle.net/2f9sq3tf/
Try accessing each of your getElementsBy functions as an array.
Example:
var elm_rows = document.getElementsByClassName("wrap")[0];
elm_rows.addEventListener("click", function (e) {
this.getElementsByTagName("input")[0].focus();
});
To resolve the remaining concern just wrap this in a loop like:
var elm_rows = document.getElementsByClassName("wrap");
for (i in elm_rows) {
elm = elm_rows[i];
elm.addEventListener("click", function (e) {
this.getElementsByTagName("input")[0].focus();
});
}
Could be better, but this works.
This should work:
let wrap = document.querySelectorAll('.wrap');
wrap.forEach((el) => {
el.addEventListener('click', (e) => {
// whatever you need to do goes here
});
});
today you can use querySelector to find elements on the DOM (and inside some NODE too).
Example:
var els = document.querySelectorAll('.wrap');
for(var i = 0; i < els.length; i++){
els[i].addEventListener('click',function(ev){
var input = ev.target.querySelector('input');
if(input) input.focus();
});
}
The if is required because with that code if you click on the input node, the event will propagate to the .wrap element, and your callback will execute too, but ev.target will be the input node and the query will return null.
var elm_rows = document.getElementsByClassName("wrap");
elm_rows[0].addEventListener("click", function (e) {
e.currentTarget.children[0].focus();
});
.wrap {border: 3px solid blue; padding: 15px;}
input {width: 100%;}
<div class="wrap">
<input type="text" name="" value="" />
</div>

Eventhandlers in a separate document

I'd like to keep all my JavaScripts in a separate document and I like it that way. Now I've had problems with the last bit of code to move from my HTML-code into my separate JavaScript document.
I got two eventhandlers that looked like this:
<a href="http://www.commercial.se" onclick="confirmLeave()" target="_blank">
and
<IMG SRC="folder/pic_small.jpg" alt="Description" onClick="view(this);">
This is the javascript code for the two eventhandlers:
function confirmLeave()
{
if(confirm("Vill du lämna Blomstermåla-Bladet?")) {
return true;
} else {
if(window.event) {
window.event.returnValue = false;
} else {
e.preventDefault();
}
return false;
}
}
And
function view(img) {
imgsrc = img.src.split("_")[0] + "_big.jpg";
viewwin = window.open(imgsrc,'viewwin', "width=790,height=444,location=0");
viewwin.focus();
}
I've managed to solve my problem of not having the javascript code in my HTML document for the first onClick eventhandler by changing my HTML to this:
<a href="http://www.commercial.com" id="external-link" target="_blank">
And adding this to my javascript document:
function init()
{
var link = document.getElementById("external-link");
link.onclick = confirmLeave;
}
window.onload = init;
I've tried adding a similar solution to the other eventhandler but I can't figure out the code I need to use for it to work. I would like to know how to add that event handler into the init function as well.
Try this
<a href="http://www.commercial.com" class="external-link" target="_blank">
<IMG SRC="folder/pic_small.jpg" alt="Description" id = "external-image">
function init() {
var link = document.getElementById("external-link");
var links = document.getElementsByClassName("external-link");
for (var i = 0; i < links.length; i++) {
links[i].onclick = confirmLeave;
}
var image = document.getElementById("external-image");
image.onclick = view;
}
window.onload = init;​
Instead of img in your function just use this
function view() {
imgsrc = this.src.split("_")[0] + "_big.jpg";
viewwin = window.open(imgsrc,'viewwin', "width=790,height=444,location=0");
viewwin.focus();
}
If you don't want to change the view function, you can do something similar, with the slight difference that you need to pass the image as an argument to the view function. You can do this by setting an anonymous function as the click handler.
<IMG SRC="folder/pic_small.jpg" alt="Description" id="some-img">
function init()
{
var img = document.getElementById("some-img");
img.onclick = function(){
view(this);
};
}

Can a JQuery plugin be called on a JQuery chain of methods or does it need to be called straight after a selector?

I'm having difficulty getting my textarea to expand vertically automatically.
I have some code to help make textarea auto expand vertically and for some reason it works when I clean out all my JS and provide a selector with reference to textarea e.g. $('textarea').autoGrow();
Calling the plugin on a chain of methods stops it from working. E.G.
micropostBox.hide().removeClass("micropost_content")
.addClass("micropost_content_expanded").show().autoGrow();
I established the plugin code works so copied all my working code to the same page and applied the autoGrow code to my textarea but it seems to be unresponsive. I noticed that the plugin I'm using the code from uses bind and unbind methods. In my code I use on and off methods from JQuery and wondering if this could be why the auto resizing of my textarea is not working?
Here is the code:
http://jsfiddle.net/erU5J/101/
autogrow plugin js code
$(function($) {
$.fn.autoGrow = function() {
return this.each(function() {
var txtArea = $(this);
var colsDefault = txtArea.attr('cols');
var rowsDefault = txtArea.attr('rows');
var updateSize = function() {
var linesCount = 0;
var lines = txtArea.attr('value').split('\n');
for (var i = lines.length - 1; i >= 0; --i) {
linesCount += Math.floor((lines[i].length / colsDefault) + 1);
}
if (linesCount >= rowsDefault) {
txtArea.attr('rows', linesCount + 1);
}
else {
txtArea.attr('rows', rowsDefault);
}
};
txtArea.unbind('.autoGrow').bind('keyup.autoGrow', updateSize).bind('keydown.autoGrow', updateSize).bind('change.autoGrow', updateSize);
});
};
});
my js code
$(function() {
$("div.microposts").on("focus", "textarea#micropostBox", function() {
var micropostForm = $(this).parent(),
micropostBox = micropostForm.find('textarea#micropostBox'),
micropostButton = micropostForm.find("input#micropostButton"),
xButton = micropostForm.find("div.xButton");
micropostBox.prop('rows', 7);
micropostForm.find('div#micropostOptions').removeClass('micropostExtraOptions');
micropostForm.find('div#postOptions').show();
$.trim(micropostBox.val()) == '' ? micropostButton.addClass("disabledMicropostButton").show()
:
micropostButton.prop('disabled', false);
micropostBox.hide().removeClass("micropost_content").addClass("micropost_content_expanded").show().autoGrow();
xButton.show();
micropostButton.prop('disabled', true);
micropostBox.off().on("keypress input change", function() {
micropostButton.prop({
disabled: !$.trim($(this).val()) != ''
});
$.trim($(this).val()) != '' ? micropostButton.removeClass("disabledMicropostButton").addClass("activeMicropostButton")
:
micropostButton.removeClass("activeMicropostButton").addClass("disabledMicropostButton");
});
xButton.on('click', function() {
micropostBox.removeClass("micropost_content_expanded").addClass("micropost_content");
micropostForm.find('div#micropostOptions').addClass('micropostExtraOptions');
micropostBox.val("");
micropostForm.find('div#postOptions').hide();
xButton.hide();
micropostButton.hide();
micropostBox.removeAttr('style');
micropostBox.prop('rows', 0);
micropostForm.find('.imagePreview > img').remove();
micropostForm.find('.imagePreview').hide();
});
});
});
$(function() {
$('div.microposts').on('click', 'li#addImage', function() {
var form = $(this).parents('form#new_micropost'),
fileField = form.find('input#micropost_image');
fileField.trigger('click');
});
});
$(function() {
$('input#micropost_image').change(function(evt) { //.off() make sautoresize work
var image = evt.target.files[0],
form = $(this).parents('form#new_micropost'),
imagePreviewBox = form.find('div.imagePreview'),
reader = new FileReader();
reader.onload = function(evt) {
var resultdata = evt.target.result,
img = new Image();
img.src = evt.target.result;
imagePreviewBox.show().prepend(img);
};
reader.readAsDataURL(image);
});
});​
textarea
<textarea class="micropost_content" cols="40" id="micropostBox" name="micropost[content]" placeholder="" rows="0"></textarea>
It would be best to view a working example on jsfiddle. My aim is to have the auto resizing of textarea working before and after an image is added to the page using the image upload button in the textarea.
Kind regards
It depends if the method preceding the plugin call returned the jQuery object containing the elements to where the plugins need to be attached.
Here are a few examples of methods that do and do not return the elements you started with:
$('element') //get an element
.contents() //get an elements contents
.wrapAll('<div>') //wrapAll contents with div and returns the contents, not wrapper
.parent() //the wrapper
.parent() //the element
.myPlugin() //we attach a plugin to element
$('<div>')
.appendTo('body') //appendTo returns the same element, the div
.myPlugin() //attaches to the div
$('element') //get an element
.text() //get its text
.myPlugin() //chaining isn't possible since text() returns a string
Better read the docs for every method in jQuery and what it returns. Some DOM methods usually return the same element, some don't, and some don't return elements but values.
In summary, can plugins be attached after chains? YES, and it depends.
Refer to the jQuery's documentation
http://docs.jquery.com/Plugins/Authoring#Maintaining_Chainability

Categories

Resources