Cant bind .change() event with dynamically generated elements - javascript

I have a button, when clicking on it the table rows and profile pic instances are generated.
Profile Pic instance which is generated:
<div class="row justify-content-center" id="owner-pic-row">
----> <div class="col-sm-2 prof-pic-col" id="col-owner-pic-1">
<div class="avatar-upload">
<div class="avatar-edit">
<input type='file' id="imageUploadOwner" accept=".png, .jpg, .jpeg" />
<label for="imageUploadOwner"></label>
</div>
<div class="avatar-preview">
<div id="imagePreviewOwner" style="background-image: url('/media/profile_images/default-profile-pic-owner.jpg');">
</div>
<p class="owner-pic-des">Owner</p>
</div>
</div>
</div> <----
</div>
The code inside ----> code <---- is generated while pressing the button
when clicking the button only one time, overall HTML code:
<div class="row justify-content-center" id="owner-pic-row">
<div class="col-sm-2 prof-pic-col" id="col-owner-pic-1">
<div class="avatar-upload">
<div class="avatar-edit">
<input type='file' id="imageUploadOwner" accept=".png, .jpg, .jpeg" />
<label for="imageUploadOwner"></label>
</div>
<div class="avatar-preview">
<div id="imagePreviewOwner" style="background-image: url('/media/profile_images/default-profile-pic-owner.jpg');">
</div>
<p class="owner-pic-des">Owner</p>
</div>
</div>
</div>
<div class="col-sm-2 prof-pic-col" id="col-owner-pic-2">
<div class="avatar-upload">
<div class="avatar-edit">
<input type='file' id="imageUploadOwner" accept=".png, .jpg, .jpeg" />
<label for="imageUploadOwner"></label>
</div>
<div class="avatar-preview">
<div id="imagePreviewOwner" style="background-image: url('/media/profile_images/default-profile-pic-owner.jpg');">
</div>
<p class="owner-pic-des">Owner</p>
</div>
</div>
</div>
</div>
Below is the JS Script for handling change event :
function readURL(input, type) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
if (type == "Owner") {
$($(input).parent().parent()).find('#imagePreviewOwner').css('background-image', "url('" + e.target.result + "')");
$($(input).parent().parent()).find('#imagePreviewOwner').hide();
$($(input).parent().parent()).find('#imagePreviewOwner').fadeIn(650);
}
}
reader.readAsDataURL(input.files[0]);
}
}
$("#owner-pic-row").on("click", "#imageUploadOwner", function() {
===> console.log($($(this).parent().parent().parent()).attr("id")) <===
$(this).change(function () {
let type = "Owner"
readURL(this, type);
});
})
Now the problem here is when ever I click on the input[id="imageUploadOwner"] in the second profile instance i.e. div[id="col-owner-pic-2"], the code inside ===> <=== prints id="col-owner-pic-1" instead of col-owner-pic-2. This means that when I change the profile pic the image is shown in the first instance everytime, regardless of which instance I want to change. The javascript code which I showed works perfectly for similar kind of logic but not here. What should I do?

Related

Custom preview images using FileReader js

I need to create custom preview the selected images. I have seen several answers about doing this and they do it by creating an img element and using appendTo to place them in a specific div. I have done this successfully as shown below in a jquery "change event"
$(document).on("change", "#file", function() {
var countFiles = $(this)[0].files.length;
var imgPreview = $("#img-preview");
for (var i = 0; i < countFiles; i++) {
var reader = new FileReader();
reader.onload = function (e) {
$("<img />", {
"src": e.target.result,
"class": "img-thumbnail"
}).appendTo(imgPreview);
}
reader.readAsDataURL($(this)[0].files[i]);
}
});
The problem I have is to preview the images with the following structure:
Here the custom structure with bootstrap
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="wraper-foto-grande d-flex justify-content-center">
<img class="img-fluid d-flex align-items-center" src="img1.jpg">
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-md-4">
<div class="wrapper-thumb d-flex justify-content-center">
<img class="img-fluid d-flex align-items-center" src="img2.jpg">
</div>
</div>
<div class="col-md-4">
<div class="wrapper-thumb d-flex justify-content-center">
<img class="img-fluid d-flex align-items-center" src="img3.jpg">
</div>
</div>
<div class="col-md-4">
<div class="wrapper-thumb d-flex justify-content-center">
<img class="img-fluid d-flex align-items-center" src="img4.jpg">
</div>
</div>
</div>
</div>
I have tried to create an array with the target.result to later use it in a function and create the structure mentioned above but I have the problem that the created array is empty. I have also seen several answers on this topic but I have not succeeded in creating the preview.
Here code:
$(document).on("change", "#file", function() {
var countFiles = $(this)[0].files.length;
var imgPreview = $("#img-preview");
var imagesArray = [];
for (var i = 0; i < countFiles; i++) {
var reader = new FileReader();
reader.onload = function (e) {
imagesArray.push(e.target.result);
}
reader.readAsDataURL($(this)[0].files[i]);
}
console.log(imagesArray.length); //show 0
console.log(imagesArray); // guess select 4 images, show 4 elements inside but I cannot access
});
My idea was to use imagesArray in a function to create the custom structure with bootstrap but I don't have access to any element.
Thanks for your help.
1st: Check if more than 1 images selected then conditionally set [col-12] class for first preview and rest of set [col-4] class & before image append in result div(#imageResults) should be empty like $('#imageResults').html('');.
2nd:
Check inline condition like i==0?'12':'4'.
Note: I added border class in image parent div for testing purpose only.
$(document).on("change", "#file", function() {
var countFiles = $(this)[0].files.length;
//Result div empty before appending new selected image
$('#imageResults').html('');
for (var i = 0; i < countFiles; i++) {
//`const columnSet` for full col-12 or col-4 class
const columnSet = (i==0?'12':'4');
var reader = new FileReader();
reader.onload = function (e) {
// Append image preview divs
$('#imageResults').append(`<div class="mb-3 col-`+columnSet+`">
<div class="border d-flex justify-content-center">
<img class="img-fluid d-flex align-items-center" src="`+e.target.result+`">
</div>
</div>`);
}
reader.readAsDataURL($(this)[0].files[i]);
}
});
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="container my-3">
<div class="row">
<div class="col-md-12">
<div class="input-group mb-3">
<label class="custom-file">
<input type="file" class="custom-file-input" id="file" accept="image/*" multiple="multiple">
<span class="custom-file-label">Choose multiple image</span>
</label>
</div>
</div>
</div>
<!-- Image Preview Area -->
<div class="row" id="imageResults">
</div>
</div>

Select parent ID always returns undefined

I am working on an application, where there is a requirement of uploading an image in the modal, and show the image in a preview div on close of the modal. I am having difficulty accessing the ID of the parent, as it always returns undefined. I am not able to figure out why this is happening. This is what I have tried so far. I am posting the necessary JS and HTML. I have a total of 4 modals each having a different ID, and functionality will work same for all 4 modals.
var $contactPhotos = $contactForm.find(".koh-contact-photo");
$contactPhotos.each(function() {
var $photoInput = $(this).find("input[type=file]");
function readURL(input) {
if (input.files && input.files[0]) {
var photoPreview = $photoInput.parent().find(".preview");
photoPreview.html("");
var reader = new FileReader();
reader.onload = function(e) {
var img = $("<img />");
img.attr("style", "height:41px;");
img.attr("src", e.target.result);
photoPreview.append(img);
}
reader.readAsDataURL(input.files[0]);
}
}
<div class="koh-contact-photo">
<span><fmt:message key='photo1' /></span> <label id="upload-1" class="button-default"><fmt:message
key='photo.upload' /></label>
<div class="preview"></div>
<button type="button" class="koh-photo-remove" style="background:#FFF;border:1px solid #77777A;">
<span class="icon" data-icon="&#xe605"></span> <span
class="label"><fmt:message key='photo.remove.text' /></span>
</button>
<!-- The Modal -->
<div id="myModal1" class="modal">
<!-- Modal content -->
<div class="modal-content">
<span class="close">×</span>
<h3 class="modal-title"> Upload Photo 1 </h3>
<div class="modal-inner">
<span>Browse for a photo</span> <label style="margin-bottom:20px;" class="button-default browse" for="photo1">BROWSE</label><input id="photo1" type="file" name="photo1" data-parsley-filesize="3" data-parsley-filetype="image/jpeg, image/png, image/gif, image/bmp"
data-parsley-trigger="change" />
<hr class="modal-hr" />
<div class="guidelines-modal">
<p> GENERAL GUIDELINES </p>
<p> Supported files are: .jpg, .gif, .png, .bmp </p>
<p> Maximum File Size: 3MB</p>
<p style="margin-bottom:10px;"> For best results: upload at 400 x 300</p>
<p> Note: images are automatically resized</p>
</div>
<div class="koh-contact-captcha modal-hr">
<!--div class="g-recaptcha" data-sitekey=<fmt:message key='kohlerSterling.google.captcha.key' />></div-->
<!--div class="g-recaptcha" id="recaptcha1"></div-->
<div id="recaptcha3" class="captcha"></div>
<div class="error-message">
<span><fmt:message key='required.field.text' /></span>
</div>
</div>
<div class="terms-modal">
<div class="checkbox">
<input type="checkbox" id="terms-condns" />
<label style="font-family:Helvetica Neue LT Pro Roman !important;font-size:12px !important;color:#000 !important;font-weight:400 !important;" for="terms-condns">I agree to the <a class="modal-anchor" href="#">Terms and Conditions</a></label>
</div>
</div>
<hr class="modal-hr" />
<div class="modal-buttons">
<label class="button-default-modal" style="margin-right:20px;">CANCEL</label>
<label class="input-button-modal">UPLOAD</label>
</div>
</div>
</div>
<input type="hidden" id="captchaKey" value="<fmt:message key='google.recaptcha.site.key'/>">
</div>
</div>
When I click on the upload button, I want to select the div with class "preview". Any help is appreciated.
.find() will get elements which are descendants of selected element.
Without looking too deep in code I think this can be part that you can improve
var photoPreview = $photoInput.parent().find(".preview"); line.
If $photoInput has a parent div with class name "preview" , you can select it with
$photoInput.parent(".preview");

Change Image on div onclick()

I want to load different image on different div clicks. How do I know which div is clicked? Do I have to pass the div class as argument?
<script type="javascript">
function ChangeLibaas() {
}
</script>
<div class="Indeximages">
<img src="images/white.png" id="libaasImage" class="img-responsive jubbahImage" alt="" />
</div>
<div class="col-md-12 nopadding customTabs">
<h2>Pick a Colour</h2>
<div class="col-md-3 colourBlue" onclick="ChangeLibaas()"></div>
<div class="col-md-3 colourBlack" onclick="ChangeLibaas()"></div>
<div class="col-md-3 colourGreen" onclick="ChangeLibaas()"></div>
</div>
Simplest inline: pass (this):
<div class="col-md-3 colourBlue" onclick="ChangeLibaas(this)"></div>
and use it :
function ChangeLibaas(theClickedDiv) {
var img = "images/"+
theClickedDiv.className.split("colour")[1].toLowerCase()+".png"; // take the colour
document.getElementById("libaasImage").src=img;
}
To make it all neater, use an attribute and unobtrusive code
window.onload=function() {
var divs = document.querySelectorAll("div.col-md-3");
for (var i=0;i<divs.length;i++) {
divs[i].onclick=function() {
document.getElementById("libaasImage").src="images/"+
this.getAttribute("data-color")+".png";
}
}
}
using
<div class="col-md-3 colourBlue" data-color="blue""></div>
You can pass as an argument, like this:
<div class="col-md-12 nopadding customTabs">
<h2>Pick a Colour</h2>
<div class="col-md-3 colourBlue" onclick="ChangeLibaas(this)"></div>
<div class="col-md-3 colourBlack" onclick="ChangeLibaas(this)"></div>
<div class="col-md-3 colourGreen" onclick="ChangeLibaas(this)"></div>
</div>
And then:
<script type="javascript">
function ChangeLibaas(sender) {
var div = sender;
}
</script>
But it's better if you use event listeners.
I hope it can be useful:
In your html
<div class="Indeximages">
<img src="images/white.png" id="libaasImage" class="img-responsive jubbahImage" alt="" />
</div>
<div class="col-md-12 nopadding customTabs">
<h2>Pick a Colour</h2>
<button class="col-md-3" data-color="colourBlue" onclick="ChangeLibaas(this)">Blue</div>
<button class="col-md-3" data-color="colourBlack" onclick="ChangeLibaas(this)">Black</div>
<button class="col-md-3" data-color="colorGreen" onclick="ChangeLibaas(this)">Green</div>
</div>
In javascript, code looks like:
function ChangeLibaas(origin) {
var color = origin.dataset.color;
var img = document.getElementById('libaasImage');
img.src = color + ".jpg";
}

change image source on submit

I want to change image source in innerHtml data when the submit button is clicked.
<div id="areaEditor">
<div class="holder">
<img src="blob.blob"/>
<input class="filesss" type="file" value="one.jpg"/>
</div>
<div class="holder">
<img src="blob.blob"/>
<input class="filesss" type="file" value="two.jpg"/>
</div>
<div class="holder">
<img src="blob.blob"/>
<input class="filesss" type="file" value="three.jpg"/>
</div>
</div>
$('#newsButton').click(function(e){
e.preventDefault();
alert("klik");
var source = $(".holder").find(".filesss").val();
var imageTag = $(".holder").find("img").attr("src",source);
var htmlData = $("#areaEditor").html();
alert(htmlData);
})
However, the htmlData I alert there only shows me that the img src for the all three image tags is one.jpg.
How to make it corrects so that the image src is based on each the closest input file there?
Many thanks for the help.
You have many .holder elements, you should loop them and get the .filesss value for each one and replace the image src as follows:
$('#newsButton').click(function(e){
e.preventDefault();
alert("klik");
$(".holder").each(function() {
var source = $(this).find(".filesss").val();
$(this).find("img").attr("src", source);
});
var htmlData = $("#areaEditor").html();
})
The idea is to loop over the elements so it can take a single value each time, in your case; you are telling JQuery to get the source from the class holder which it finds it in the first element, so it does not need to look for anything else.
So you can do something like:
<div id="areaEditor">
<div class="holder">
<img src="blob.blob"/>
<input class="filesss" type="file" value="one.jpg"/>
</div>
<div class="holder">
<img src="blob.blob"/>
<input class="filesss" type="file" value="two.jpg"/>
</div>
<div class="holder">
<img src="blob.blob"/>
<input class="filesss" type="file" value="three.jpg"/>
</div>
</div>
<script>
$('#newsButton').click(function(e){
e.preventDefault();
alert("klik");
$(".holder").each(function() {
var source = $(this).find(".filesss").val();
$(this).find("img").attr("src",source);
});
var htmlData = $("#areaEditor").html();
alert(htmlData);
})
</script>

Showing Overall Description on button click

I have a UI where more than three div's are there which has the data's with different ids but with the common button called as "Read".I have displayed the messages in which I have kept the message body as a tiny(15) on this Read button it show me the entire body of the message.How to achieve this one way that I am trying to do is as follows:
foreach (var item in Model.MyNote)
{
<div class="row">
#if (item.Owner.Roles.Any(cx => cx.RoleName == "Customer"))
{
<div class="panel">
<div class="row">
<div class="three columns">
<img src="#Request.Url.FormatAbsoluteUrl(#item.Owner.Personal.ImageURL)" />
<span style="text-align: center;">
#item.Owner.Personal.FirstName #item.Owner.Personal.LastName
</span>
</div>
<div class="nine columns">
<input type="hidden" value="#item.Id" id="messid" />
<p class="parahide1">#item.Description </p>
<p class="parahide">#item.Description.ToTiny(15) </p>
</div>
#*Read*#
<button class="button" id="read">Read</button>
</div>
</div>
}
else if (item.Owner.Roles.Any(cx => cx.RoleName == "Professional"))
{
<div class="panel">
<div class="row">
<div class="nine columns">
<p>#item.Description </p>
</div>
<div class="three columns">
<img src="#Request.Url.FormatAbsoluteUrl(#item.Owner.Professional.ImageURL)" />
<span style="text-align: center;">#item.Owner.Professional.CompanyName</span>
</div>
</div>
Read
</div>
}
</div>
<script type="text/javascript">
$(function () {
$(".parahide1").hide();
$("#read").live('click',function () {
$(".parahide").hide();
$(".parahide1").show();
});
});
</script>
}
This give the the result but it is showing the description of all the div's even if I click on the button of the first div.
Try finding the classes in the parent of the current button like this -
$(function () {
$(".parahide1").hide();
$("#read").on('click',function () {
$(this).parent().find(".parahide").hide();
$(this).parent().find(".parahide1").show();
});
});
Hence, only the divs present in the current button's parent will be hidden or shown!
More on .parent() and .find()
Also use .on() instead of .live() as live has been deprecated.

Categories

Resources