Select parent ID always returns undefined - javascript

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

Related

Multiple instances of "add another photo" button - show div

I have a div that contains a file uploader. Next to this, there is an 'Add Photo' button.
This button once clicked should be hidden, and then reveal another file uploader div with another 'Add Photo' button, which will in turn hide/reveal another button & div upon click.
Anyone able to help? Apparently I cannot just copy the JS and repeat it to affect other ID's
const btn = document.getElementById('btnhide');
btn.addEventListener('click', () => {
btn.style.display = 'none';
// 👇️ show div
const box = document.getElementById('myDIV1');
box.style.display = 'block';
});
<div class="form-content block">
<div class="one">
<label>Photo Upload <em class="tooltip">*<span class="tooltiptext">Required</span></em></label>
</div>
<div class="two">
<input type="file" name="FileUpload" checktype="c1">
<p id="FileUpload_error" style="display: none;">Choose any file for this field.</p>
<p>Please make sure each photo is 20MB or less, thank you. <button id="btnhide" type="button">Add Photo</button></p>
</div></div>
<div class="form-content block" id="myDIV1" style="display:none;">
<div class="one">
<label>Photo Upload <em class="tooltip">*<span class="tooltiptext">Required</span></em></label>
</div>
<div class="two">
<input type="file" name="FileUpload1" checktype="c1">
<p id="FileUpload_error1" style="display: none;">Choose any file for this field.</p>
<p>Please make sure each photo is 20MB or less, thank you. <button id="btnhide1" type="button">Add Photo</button></p>
</div></div>
<div class="form-content block" id="myDIV2" style="display:none;">
<div class="one">
<label>Photo Upload</label>
</div>
<div class="two">
<input type="file" name="FileUpload2" checktype="c1">
<p id="FileUpload2_error" style="display:none;">Choose any file for this field.</p>
<p>Please make sure each photo is 20MB or less, thank you. <button id="btnhide2" type="button">Add Photo</button></p>
</div></div>
From the question comments:
I am following the [HTML] ... supplied ... as I am too inexperienced to
build from scratch.
So...without changing any HTML provided in the question...
...use Javascript to add a click event listener to each "Add Photo" button, that when clicked will navigate to its parent photo upload div, get the next photo upload div, display that, and finally hide itself (button only):
// get all buttons within divs having className "form-content button"
const btns = document.querySelectorAll("div.form-content button");
// interate over resulting button array
btns.forEach((btn, ii) => {
// add a click event listener to each one
btn.addEventListener("click", evt => {
// navigate up to the parent "form-content block" div
// then get the next sibling and assign to photoupload
// DIV.form-content+block > DIV.two > P > BUTTON
const photoupload = evt.target.parentNode.parentNode.parentNode.nextElementSibling;
// if the next sibling is also a "form-content block" div, i.e., this is not the last photoupload,
// display the next "form-content block" div
if ( "form-content block" === photoupload.className ) {
photoupload.style.display = "block";
}
// hide this "Add Photo" button
btn.style.display = "none";
});
// and hide last "Add Photo" button——to not perplex people
if ( btns.length - 1 === ii ) { btn.style.display = "none"; }
});
<div class="form-content block">
<div class="one">
<label>Photo Upload <em class="tooltip">*<span class="tooltiptext">Required</span></em></label>
</div>
<div class="two">
<input type="file" name="FileUpload" checktype="c1">
<p id="FileUpload_error" style="display: none;">Choose any file for this field.</p>
<p>Please make sure each photo is 20MB or less, thank you. <button id="btnhide" type="button">Add Photo</button></p>
</div></div>
<div class="form-content block" id="myDIV1" style="display:none;">
<div class="one">
<label>Photo Upload <em class="tooltip">*<span class="tooltiptext">Required</span></em></label>
</div>
<div class="two">
<input type="file" name="FileUpload1" checktype="c1">
<p id="FileUpload_error1" style="display: none;">Choose any file for this field.</p>
<p>Please make sure each photo is 20MB or less, thank you. <button id="btnhide1" type="button">Add Photo</button></p>
</div></div>
<div class="form-content block" id="myDIV2" style="display:none;">
<div class="one">
<label>Photo Upload</label>
</div>
<div class="two">
<input type="file" name="FileUpload2" checktype="c1">
<p id="FileUpload2_error" style="display:none;">Choose any file for this field.</p>
<p>Please make sure each photo is 20MB or less, thank you. <button id="btnhide2" type="button">Add Photo</button></p>
</div></div>
Using Javascript functions and properties: querySelectorAll(), forEach(),
addEventListener(), event.target, parentNode, nextElementSibling, and className.

How to use divs as radio button and save data from inside the selected div to valiables using javascrip?

I have multiple divs in my HTML with sample class name and I want these divs to behave like a radio button, that is when a div is clicked / selected, I want to achieve following.
1: Change the selected div background color
2: Get values from different elements those are inside the selected div and save the values in variables.
I am able to change the color but I am not able to get the unique values from inside the selected div.
Here is the HTML
<div class="col-lg-4 text-center">
<div class="package">
<input type="hidden" class="packageId" value="5" />
<p class="small">Deep</p>
<h4 class="packageTitle">Deep Cleaning</h4>
<p>All-inclusive cleaning service</p>
<p class="small">Price Per Cleaner</p>
<p class="price packagePrice">41.90 <span class="small">/h</span></p>
</div>
</div>
<div class="col-lg-4 text-center">
<div class="package">
<input type="hidden" class="packageId" value="4" />
<p class="small">Last Minute</p>
<h4 class="packageTitle">Last-Minute Cleaning</h4>
<p>Last minute & after party cleaning</p>
<p class="small">Price Per Cleaner</p>
<p class="price packagePrice">43.90 <span class="small">/h</span></p>
</div>
</div>
<div class="col-lg-4 text-center">
<div class="package">
<input type="hidden" class="packageId" value="3" />
<p class="small">Moving</p>
<h4 class="packageTitle">Move-In-Out Cleaning</h4>
<p>For move-ins, and move-outs</p>
<p class="small">Price Per Cleaner</p>
<p class="price packagePrice">41.90 <span class="small">/h</span></p>
</div>
</div>
And here the the Script
var packageId = "";
var packageTitle = "";
var packagePrice = "";
var packages = document.getElementsByClassName('package');
Array.prototype.forEach.call(packages, function (element) {
element.addEventListener('click', function () {
$('.package').css("background-color", "#FFFFFF");
$(this).css("background-color", "#FCF6CC");
packageId = $('.packageId').attr('value');
packageTitle = $('.packageTitle').text();
packagePrice = $('packagePrice').text();
console.log(packageId);
console.log(packageTitle);
console.log(packagePrice);
});
});
The reason that youre not getiing the unique value is because you are using get element by class ,
ie packagePrice = $('.packagePrice').text();
and there are 3 elements with same class name , to fix this issue
const elem = $(this);
packagePrice = elem.find('.packagePrice').text();

Cant bind .change() event with dynamically generated elements

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?

How to filter image gallery by tags using Javascript?

I've been struggling to understand how to overcome this problem. I've been tasked to retrieve user input, and on keystroke see if user input matches any amount of .tags If not, hide the .thumb-display.
So far, I've been able to gather that I'll need to add/remove the classlist "hidden" as well use the event handler "input", however I don't quite understand how to use event handler "input" in this context as well as change event.
This is for homework so I'd much rather have an explanation for an answer, rather than just an answer so I can understand what I currently can't. Even a hint could be vital and set me on the right track! Rules are: no changing HTML and must use JavaScript.
Here is the HTML:
<form class="frm-filter">
<div class="frm-group">
<a class="reset hidden" href="#">Reset</a>
<input class="frm-control" type="text" id="filter" name="filter" placeholder="tag filter" />
</div>
</form>
</nav>
<section class="gallery">
<div class="row">
<h1>Gallery</h1>
</div>
<div class="row">
<div class="thumb-display">
<img src="img/thumbs/african_road_to_the_mountain.jpg" alt="african road to the mountain" />
<p class="tags">#africa #mountain #road</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/beach_and_palms.jpg" alt="beach and palms" />
<p class="tags">#palmbeach #distantpeaks</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/beach_road.jpg" alt="beach road" />
<p class="tags">#oceanbeach #mountainroad</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/calm_lake.jpg" alt="calm lake" />
<p class="tags">#lake #clearskies #onthewater</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/fall_bridge.jpg" alt="fall bridge" />
<p class="tags">#fallcolors #bridgecrossing #river</p>
</div>
</div>
</section>
You need to listen on input keyup event and retrieve value from input then check if that value matches any tags and show/hide `parentNode
document.addEventListener('DOMContentLoaded', () => {
const inputEl = document.getElementById('filter');
const tags = Array.from(document.querySelectorAll('.tags'));
inputEl.addEventListener('keyup', () => {
const value = inputEl.value;
tags.forEach(tag => {
if (tag.textContent.includes(value)) {
tag.parentNode.style.display = 'block'
} else {
tag.parentNode.style.display = 'none'
}
})
})
})
<form class="frm-filter">
<div class="frm-group">
<a class="reset hidden" href="#">Reset</a>
<input class="frm-control" type="text" id="filter" name="filter" placeholder="tag filter" />
</div>
</form>
<section class="gallery">
<div class="row">
<h1>Gallery</h1>
</div>
<div class="row">
<div class="thumb-display">
<img src="img/thumbs/african_road_to_the_mountain.jpg" alt="african road to the mountain" />
<p class="tags">#africa #mountain #road</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/beach_and_palms.jpg" alt="beach and palms" />
<p class="tags">#palmbeach #distantpeaks</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/beach_road.jpg" alt="beach road" />
<p class="tags">#oceanbeach #mountainroad</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/calm_lake.jpg" alt="calm lake" />
<p class="tags">#lake #clearskies #onthewater</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/fall_bridge.jpg" alt="fall bridge" />
<p class="tags">#fallcolors #bridgecrossing #river</p>
</div>
</div>
</section>
You need to get user input. So you need to listen for an event. Add Event Listener to the rescue. Which event, though? How about "change".
Ok, so you can get what they typed, good. Now you need to compare it to the tags. So it's time to find all of those. You can get all of the ".tags" with a querySelector. That will get you a list of nodes that you can loop through to collect the innerText. You can check if the innerText includes the input that the user typed. If it doesn't, then you find the closest ".thumb-display" and set a style attribute to hide it. If the input IS in the innerText, then you need to remove any style attribute that is hiding the closest parent.
Boom, done. Maybe, I didn't try it an I almost never get it right the first time. But it would be something along those lines.

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