Getting the child img inside a div using $(this); [on click event] - javascript

I'm trying to get the child image of a clicked div.
I want to get it's src value. But it's returning undefined.
Could someone point me in the right direction?
Tried using Jquery .find() https://api.jquery.com/find/
Tried using Jquery .children() https://api.jquery.com/children/
Both return undefined.
for (let i = 0; i < $('#draw-raster > div').length; i++) {
$(document).on('click', '#raster-item'+i, () => {
let image = $(this).children('img').attr('src'); //undefined
let image2 = $(this).find('img').attr('src'); //undefined
if (image) {
console.log(image);
return alert("image child found!");
}
return setTimeout(() => {
$('#raster-item'+i).children('img').hide();
}, 4500);
});
$('#image'+i).hide();
}
load html:
for(let i = 0; i < 16; i++)
{
let image = displayImages();
$('#draw-raster').prepend(
"<div id=raster-item" + i + " class='imageh"+i+"' data-id=" + i + "><img src='"+ displayImages() +"' class='image "+i+"' id='image"+ i +"' alt='Failed to load image' width='173.19' height='107.3'></div>"
);
}
html page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Memory</title>
<script src="inc/js/jquery.min.js"></script>
<link rel="stylesheet" href="inc/css/boostrap.min.css">
<link rel="stylesheet" href="inc/css/memory.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<div class="container justify-content-center">
<div class="wrapper">
<div class="row">
<div class="col-lg-9">
<div class="card">
<div class="card-header bg-dark" style="color:white;">
<h2>Memory</h2>
</div>
<div class="card-body">
<section class="col-12 mx-auto" id="draw-raster">
</section>
</div>
</div>
</div>
<div class="col-lg-3">
<div class="card">
<div class="card-header bg-dark" style="color:white;">
<h2>Turns</h2>
</div>
<div class="card-body">
<div id="turns">Turns: 0</div>
<div id="sets">Sets: 0</div>
</div>
</div>
<div class="form-group">
<button class="btn btn-success col-12" type="button" id="reset">Reset scores</button>
</div>
</div>
</div>
</div>
</div>
<script src="inc/js/memory.js"></script>
</body>
</html>
Both attempts return undefined, i'm uncertain what would work.
Yes, I've been spamming google too. :'^)

A couple of notes on your code:
1) If you want to use this you'll need to switch from an arrow function back to a regular anonymous function. Arrow functions don't have a this of their own and will borrow the context from their outer lexical environment. It's why your code keeps return undefined.
2) You don't need a loop. The benefit of using jQuery is that you can operate on collections of elements all at once. In your case you're attaching a single event listener to a parent element (here: document) and waiting for events to bubble up from the .raster-item imgs and be "captured". This is called event delegation and is useful when you want to process new elements added to the DOM after it has loaded.
2) You will find it easier to use a class instead of many ids.
Here's an example based on your code with these changes:
// Use event delegation to add an event listener to the element with
// the container class that watches out for click events on **all**
// elements with the raster-item class that contain images
$('.container').on('click', '.raster-item img', function () {
// `$(this)` will be the image element, so simply grab its src
// from the attribute
console.log($(this).attr('src'));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="raster-item"><img src="https://dummyimage.com/50x50/555/fff.png" /></div>
<div class="raster-item"><img src="https://dummyimage.com/50x50/777/fff.png" /></div>
<div class="raster-item"><img src="https://dummyimage.com/50x50/999/fff.png"/></div>
<div class="raster-item"><img src="https://dummyimage.com/50x50/bbb/fff.png" /></div>
</div>

You don't need jQuery for this. You can harness the power of event bubbling with vanilla JavaScript.
In the web page below, the code inside the script tags, listen for a click event and runs some code if that event happens, i.e. bubbles, through a DIV element:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Clicked div img</title>
</head>
<body>
<div class="catcher">
<p>This is a div with an image inside</p>
<img src="image-to-pick.jpg" alt="image to pick" ()>
</div>
<script>
document.addEventListener('click', function (event) {
if (event.target.tagName == 'DIV') {
var imgToPick = event.target.querySelector('img');
console.log(imgToPick.src); // add your code here
}
}, false);
</script>
</body>
</html>
In other words, you trigger a "click event" whenever you click on that page, that event bubbles up until it reaches the root of the HTML document (which you can imagine as an upside-down tree where the root is the html tag).
If you don't need or don't want to let it bubble to the elements "above" you DIV, you can also stop the propagation of that click event by using event.stopPropagation(), right after you handle the img src.
You can find more info about how this works here on MDN (Mozilla Dev. Network)

I'm not quite sure in what context you need to do this, but with jquery it's pretty straight forward.
If you have multiple images within a parent div, you can set the child images as the selecters for the click event, and return each image src when clicked on directly.
The resulting jquery is only three lines long this way, and you can add as many images as you like to the parent div:
<div class="image-container">
<img id="first" src="first-source-goes-here.jpg" alt="img text" />
<img id="second" src="second-source-goes-here.jpg" alt="img text" />
<img id="third" src="third-source-goes-here.jpg" alt="img text" />
</div>
$(".image-container > img").click(function() {
// replace 'alert' with what ever you need it to be
alert( $(this).attr("src") )
})
EDIT:
In response to Andy's comment on my answer below, if you are loading images once the DOM has been loaded, then you could run a check on the click parent div to see if there are any images within it before returning the source:
$(".image-container").click(function() {
if( $(this).children("img").length > 0 ) {
alert( $(this).find("img").attr("src") )
} else {
alert('there are no images here')
}
})

Related

How to best get the parent of parent element in javascript

I'm trying to get the parent of some deeply nested element like below
<div class='content id='cart-content'>
<div class='child1'>
<div class='child1-1'>
<div class='child1-1-1'>
<input
type="checkbox"
class='selectAllItem'
name='selectAllItem'
/> Select All
</div>
</div>
</div>
<div class='child2'>
<div class='child2-2'>
<div class='child2-2-2'>
<input
type="checkbox"
class='selectOneItem'
name='selectOneItem'
/> Select One
</div>
</div>
</div>
</div>
when i check Select All box I want to get the node of the root parent which have id='cart-content'
my approach
1.
let rootNode = event.target.closest('#cart-content')
but the problem is clicking on select one checkbox would also return same result because they both have same root parent and are on same level
approach 2.
let rootNode = event.target.parentNode.parentNode.parentNode.parentNode;
the problem with this approach is the same if i click on select one checkbox would also return the root parent because the distance between the element and the root parent is also 4 parents
Now in jquery i would do the below to get desire result
let rootNode = $(this).parent('.child1-1-1').parents('#');
and when select one is clicked it won't return the rootNode because it doesn't have a direct parent with the class name child1-1-1
How can I achieve this same result using pure javascript vanilla js
Thanks for any help
This is my approach to solve the problem
get the immediate parent of the input field then check if it contails a specific class
var rootParentNode = e.target.parentNode.classList.contains('child1-1-1') ? e.target.closest('#cart-content') : null;
I think you only need to add an unique id to your input dynamically (not hard coding as I do below) and then just do what you want with the parentNode only if your input id is number 1, for instance (Select All) and nothing if it is number 2 (Select One).
Note that the event is listening to changes on check box, not to the checked status
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Static Template</title>
</head>
<body>
<h1>
This is a static template, there is no bundler or bundling involved!
</h1>
<div class="content" id="cart-content">
<div class="child1">
<div class="child1-1">
<div class="child1-1-1">
<input
id="input1"
type="checkbox"
class="selectAllItem selectinput"
name="selectAllItem"
/>
Select All
</div>
</div>
</div>
<div class="child2">
<div class="child2-2">
<div class="child2-2-2">
<input
id="input2"
type="checkbox"
class="selectOneItem selectinput"
name="selectOneItem"
/>
Select One
</div>
</div>
</div>
</div>
</body>
<script>
let allInputs = document.getElementsByClassName("selectinput");
allInputs = [...allInputs];
allInputs.forEach((input) => {
input.addEventListener('change', (e) => {
let parentNode;
if (e.target.id == "input1") {
parentNode = e.target.parentNode.parentNode.parentNode.parentNode;
// Do something with parentNode
console.log(parentNode)
}
else{
// Do something else
}
});
});
</script>
</html>

Change image src to a local image using javascript?

First time ever touching javascript here, so bear with me.
My file structure looks like so:
I want to change the image in my HTML using js. Here's the relevant HTML code:
<!DOCTYPE html>
<html>
<head>
<title>Assignment 3A</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="style/assignment_3.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="data/data.js"></script>
<script src="script/htmlMaker.js"></script>
<script src="script/assignment_3.js"></script>
<script id="news-detail-template" type="text/html">
<img class='news_photo' src='{{photo}}' >
<div class='news_heading'>{{heading}}</div>
<div class='date'>{{Date}}</div>
<div class='news_detail'>{{details}}</div>
</script>
<script id="news-item-template" type="text/html">
<div news_id='{{id}}' class='news_item' > {{heading}} </div>
<img class='news_img' src='data/NBA.jpg'>
</script>
</head>
<body>
<div class="newsDiv">
<div class="left">Latest</div>
<div id="news" class="marquee"></div>
<img id="toggle" class="right" src="data/pause.png" onclick="toggle(this)">
</div>
<div id="detail" class="detail">
</div>
</body>
</html>
And then the corresponding js code in assignment_3.js:
function toggle(image) {
if (image.src != "data/pause.png")
{
image.src='data/pause.png';
}
else if (image.src == "data/pause.png")
{
image.src='data/play.png';
}
}
Obviously, something is amiss here, as the browser doesn't seem to recognize my image paths at all. How would I go about doing this correctly?
When you use image.src, it returns the full path of the image. In the if condition, you only checks the relative path of the image. To check for the relative path of the image, you can use image.getAttribute('src').
function toggle(image) {
if (image.getAttribute('src') == "data/pause.png") {
image.setAttribute('src', 'data/play.png');
} else {
image.setAttribute('src', 'data/pause.png');
}
}
<body>
<div class="newsDiv">
<div class="left">Latest</div>
<div id="news" class="marquee"></div>
<img id="toggle" class="right" src="data/pause.png" onclick="toggle(this)">
</div>
<div id="detail" class="detail">
</div>
</body>
I have modelled a minimal, complete and verifiable example of your problem in this JSFiddle. I don't see any issues in your toggle logic. The only thing you need to consider is using img.getAttribute('src') instead of img.src. This is because
img.getAttribute('src') - Gives you the actual value that the HTML markup has set
img.src - Effective absolute path of the source
function toggle(img) {
// var playSrc = "data/play.png"; // to use your file instead
var playSrc = "https://cdn.iconscout.com/icon/premium/png-256-thumb/play-button-1516951-1285078.png";
// var pauseSrc = "data/pause.png"; // to use your file instead
var pauseSrc = "http://www.pngall.com/wp-content/uploads/5/Pause-Button-Transparent.png";
if (img.getAttribute('src') != pauseSrc)
{
img.setAttribute('src', pauseSrc);
}
else // The part if (image.src == "data/pause.png") is redundant
{
img.setAttribute('src', playSrc);
}
}
With that out of the way, you have a lot of junk in the <head> tag, which you need to remove (I have put them below). Probably, the code isn't working because of that.
<script id="news-detail-template" type="text/html">
<img class='news_photo' src='{{photo}}' >
<div class='news_heading'>{{heading}}</div>
<div class='date'>{{Date}}</div>
<div class='news_detail'>{{details}}</div>
</script>
<script id="news-item-template" type="text/html">
<div news_id='{{id}}' class='news_item' > {{heading}} </div>
<img class='news_img' src='data/NBA.jpg'>
</script>
As Harshana points out, you need to use the getAttribute function to check equality. You can set the image source using a regular assignment operator, but you cant use == to check for equality.

How can I insert an image on click in Javascript?

So I'm new to JavaScript and I have a list and when that list item is clicked, I want an image to appear, and only when it's clicked. How can I go about doing this through my JS document? I went ahead and made an ID for one of my list documents that I can use for my JS.
<div class="tab-pane active full" id="status" role="tabpanel">
<ul class="item-list">
<li><a id="pipboy_gun_img" href="#" class="44_pistol">.44 Pistol</a></li>
<li>10mm Pistol</li>
<li>Assault Rifle</li>
</ul>
In javascript, if you apply an event listener to a parent element, all the child elements of it are also listening to that event. So you can apply a click event to the <ul>. So all the <li> items are listening to that event.
Then use a switch case to switch between different click events.
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<script>
document.addEventListener('DOMContentLoaded' , function(){
var list = document.getElementById('allList');
var image = document.getElementById('targetImg');
list.addEventListener('click' , function(e){
switch(e.target.textContent){
case '44 Pistol':
image.setAttribute("src" , "https://www.pewpewtactical.com/wp-content/uploads/2019/12/8.-Glock-44-.22LR.jpg");
break;
case '10mm Pistol':
image.setAttribute("src" , "https://www.airgundepot.com/vault/wp-content/uploads/2016/08/Other-Pistol-Options.jpg");
break;
case 'Assault Rifle':
image.setAttribute("src" , "https://images-na.ssl-images-amazon.com/images/I/819LnIT7GSL._AC_SL1500_.jpg");
break;
default:
break;
}
})
})
</script>
<body>
<div class="tab-pane active full" id="status" role="tabpanel">
<ul class="item-list" id="allList">
<li><a id="pipboy_gun_img" href="#" class="44_pistol">44 Pistol</a></li>
<li>10mm Pistol</li>
<li>Assault Rifle</li>
</ul>
<img height="400px" width="400px" id="targetImg" src="" alt="">
</body>
</html>
side note: If you wondering what is this DOMContentLoaded, It prevents the javascript part is being executed before the HTML DOM is loaded.
If you don't want to use it just cut and paste <script> **your java script code ** </script> below the body tag.

JavaScript Removing Elements Dynamically! removeChild

Technology I am using is materialize and vanilla js. I've created a materialize button that opens a model. within the model is a form that takes user input, then places the input text onto the main page, when the Submit button is triggered. then I have a button that should remove/delete the input posted. So the issue I'm having is that the JavaScript linked to the button which should delete/removeChild isn't working. please help :)
// ----------------Models Materialize Framework----------------
document.addEventListener('DOMContentLoaded', () => {
var elems = document.querySelectorAll('.modal');
var instances = M.Modal.init(elems);
});
//Delete From The Dom
const delExerciseBtn = document.querySelector('.del-exercise-btn');
delExerciseBtn.addEventListener('click', (e) => {
if(e.target.className == 'delete'){
const h6 = e.target.parentElement;
delExerciseBtn.removeChild(h6);
}
});
// Add User's To the Dom.
const addExerciseDom = document.querySelector('.exercise-dom');
const exerciseForm = document.querySelector('.exercises-form');
const disabledExersiceBtn = document.querySelector('.disabled-exersicebtn');
exerciseForm.addEventListener('submit', (e) => {
e.preventDefault();
// Get Input Value
const value = exerciseForm.querySelector('input[type="text"]').value;
// Create Elements
const h6 = document.createElement('h6');
// Add Content
h6.textContent = value;
// Append To Dom
addExerciseDom.appendChild(h6);
//Disable Btn
disabledExersiceBtn.setAttribute('disabled', 'disabled');
});
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<!-- Google icons -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet">
<!-- Compiled and minified CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<!-- Sytle.css -->
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<!----- user's input ------->
<div class="row">
<div class="col s12 center valign-wrapper center-align">
<div class=" exercise-dom delete"> <!--Users text input h6----> </div>
</div>
</div>
<!-- Btn/Modals/form -->
<div class="row">
<!-- Dom Btn -->
<div class="col s12 center ">
<a href="#exercise" class="btn-floating btn-small darken-4 z-depth-2 black center modal-trigger disabled-exersicebtn">
<i class="material-icons white-text">add </i>
</a>
</div>
<!-- Modal/form -->
<div class="modal modal-position" id="exercise">
<div class="modal-content">
<div class="row exercises-padding">
<form class="col s12 exercises-form" autocomplete="off">
<div class="input-field col s10">
<i class="material-icons prefix">fitness_center</i>
<input type="text" id="autocomplete-input" class="autocomplete center">
<label for="autocomplete-input" ><h6>Exercises</h6></label>
</div>
<div class="modal-footer">
<input class="modal-close btn black" type="submit" value="Submit">
</div>
</form>
</div>
</div>
</div>
<!-- Remove Users Btn -->
<div class="col s12 center remove-padding">
<a href="#" class="btn-floating btn-small darken-4 z-depth-2 black center modal-trigger del-exercise-btn">
<i class="material-icons white-text ">remove </i>
</a>
</div>
<!-- Compiled and minified JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<!-- app.JavaScript -->
<script src="app.js"></script>
</body>
</html>
Update:
you have a nesting error in your HTML, a </div> is missing, which is why the DOM doesn't contain the form
check the DOM with developer tools by inspecting elements, and you'll see that the structure is wrong
you can also use for example Codepen's "Analyze HTML" function in the HTML pane to check your HTML
the <form>'s class is Exercises-form, and the selector .exercises-form (from const exerciseForm = document.querySelector('.exercises-form');) therefore can't find the element, as CSS class names are case-sensitive. exerciseForm then becomes null, which causes the error Uncaught TypeError: Cannot read property 'addEventListener' of null
the delete button still doesn't work. I suggest to you try for yourself. Use the browser developer tools, especially the DOM element inspector and the console for interactive tests for your selector queries (and the element you select in the element inspector is accessible as $0 in the console.). There are many tutorials a Google search away.
Additional note: I oversaw that there's already an document.addEventListener('DOMContentLoaded', () => {... at the top of the file. You can put your code there, no need for another DOMContentLoaded event listener (although it doesn't hurt either).
Original answer:
You get
Uncaught TypeError: Cannot read property 'addEventListener' of null
that means that
const delExerciseBtn = document.querySelector('.del-exercise-btn');
couldn't find the node and returned null.
Probable reason: code runs too early, browser has not yet constructed the DOM.
Solution: wrap your code in a DOMContentLoaded event handler:
window.addEventListener('DOMContentLoaded', (event) => {
const delExerciseBtn = document.querySelector('.del-exercise-btn');
// ...
});
const h6 = e.target.parentElement;
delExerciseBtn.removeChild(h6);
You are trying to remove its parent from a button. And you need to remove the button from the parent.
const h6 = e.target.parentElement;
h6.removeChild(e.target);

Use jquery to set onfocus event for only img in <a</a> tags

I have this piece of code :
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div class="container">
<p class="demo">test </p>
<a href="xx" class="focusme">
<img src="images/testimage.gif" alt="" >
</a>
<a href="xx" class="focusme">
<img src="images/testimage.gif" alt="">
</a>
</div>
<script type="text/javascript" src="js/jquery.2.1.4.min.js"></script>
<script>
$(function () {
$(".focusme").focus(function(){
$(this).img.invert();
});
});
</script>
</html>
What I want to do is to invert the images when the <a> tag got focus, but I'm stuck to register the focus and blur event for them.
Here is what I'm trying to achieve :
for example, the html :
<a href="xx" class="focusme">
<img src="images/testimage.gif" alt="" id="img1">
</a>
So at this point, it's easy to access the img above because it has an ID :
$("#img1").invert();
but what i want is :
$(function () {
$(".focusme").focus(function(){
var img = $(this).img;
img.invert();
});
});
P/s : the invert() function is from a seperated js file, and is working well if I manually call it like this :
$("#img1").invert();
How can this be done?
Use the focus on <a> and use find() for the image
$(function () {
$("a.focusme").focus(function(){
$(this).find('img').invert();
});
});
The problem is that <img> tags cannot be focused by default. However, you can allow them to be focused by setting the tabIndex property.
$(".focusme").each(function(i) {
$(this).attr('tabIndex', i + 1)
})
After adding that, your code will be executed when you click on the images, and when you tab between them.
example: http://codepen.io/anon/pen/xZzzOm?editors=1010

Categories