Can't read the NodeName of a parent element - javascript

I want to build a script which recognizes the index of an (unspecified) element within its parent element with an simple mouseclick. It's possible that the clicked element is a span, div, li or any other element.
Problem is that I am not able to retrieve the TagName / NodeName of the parent element because I always get an error Uncaught TypeError: Cannot read property 'nodeName' of undefined
My HTML looks like that:
<body>
<span id="test1">
<div>test</div>
</span>
<div id="test2">
<div>eins</div>
<div>zwei</div>
<div>drei</div>
</div>
</body>
My function looks like that:
$(document).on('click', function(evt){
evt.stopPropagation();
var child = evt.target.tagName;
var parent = $(evt).parent();
console.log(parent[0].nodeName);
});
According to this StackOverflow thread this should be right, but it doesn't work.

I want to build a script which recognizes the index of an (unspecified) element within its parent ...
So you just need to use $.fn.index method with evn.target which points to clicked element:
$(document).on('click', function(evt) {
var index = $(evt.target).index();
alert(index);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id="test1">
<div>test</div>
</span>
<div id="test2">
<div>eins</div>
<div>zwei</div>
<div>drei</div>
</div>

Seems that -
$(evt).parent();
Should be -
$(evt.target).parent();

Related

jQuery ID Return is undefined although HTML ID is defined

I'm trying to retrieve the ID of one element, store it as a variable and then use that ID value to interact with other elements in that section with the same ID.
<div class="mainContent">
<div class="articleContent">
<h1>header1</h1>
<p class="articlePara" id="one">para1</p>
</div>
<div class="articleFooter" id="one" onclick="readMore()">
</div>
</div>
<div class="mainContent">
<div class="articleContent">
<h1>header2</h1>
<p class="articlePara" id="two">para2</p>
</div>
<div class="articleFooter" id="two" onclick="readMore()">
</div>
</div>
And then the JS/jQuery
function readMore() {
var subID = event.target.id;
var newTarget = document.getElementById(subID).getElementsByClassName("articlePara");
alert(newTarget.id);
}
At this point I'm only trying to display the ID of the selected element but it is returning undefined and in most cases people seem to notice that jQuery is getting confused because of the differences between DOM variables and jQuery ones.
jsfiddle: https://jsfiddle.net/dr0f2nu3/
To be completely clear, I want to be able to click on one element, retrieve the ID and then select an element in the family of that clicked element using that ID value.
just remove the getElementsByClassName("articlePara"); in end of the newTarget .already you are call the element with id alert the element of the id is same with target.id
function readMore() {
var subID = event.target.id;
var newTarget = $('[id='+subID+'][class="articlePara"]')
console.log(newTarget.attr('id'));
console.log(newTarget.length);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="mainContent">
<div class="articleContent">
<h1>header</h1>
<p class="articlePara" id="one"></p>
</div>
<div class="articleFooter" id="one" onclick="readMore()">click
</div>
</div>
As you have read before, you should keep your id's unique, and you should avoid using onclick in html, but you could do it like this.
With querySelector you get the element and then with parentElement you can retrieve the parent of that element.
function readMore(el) {
var articleFooterId = el.id;
var articlePara = document.querySelector(".articleContent #"+articleFooterId);
var articleContent = articlePara.parentElement;
console.log('articleFooter', articleFooterId);
console.log('articlePara', articlePara);
console.log('articleContent', articleContent);
}
In your html you can return the 'this' object back to the function by doing readMore(this).
<div class="mainContent">
<div class="articleContent">
<h1>header1</h1>
<p class="articlePara" id="one">para1</p>
</div>
<div class="articleFooter" id="one" onclick="readMore(this)">footertext</div>
</div>
<div class="mainContent">
<div class="articleContent">
<h1>header2</h1>
<p class="articlePara" id="two">para2</p>
</div>
<div class="articleFooter" id="two" onclick="readMore(this)">footertext</div>
</div>
jsfiddle
if you're using Jquery:
$(function () {
$('div.articleFooter').click(function () {
var para = $(this).prev().find('p.articlePara').text();
alert('T:' + para);
});
})
$('.articleFooter').click(function() {
var b=subId; //can be any
var a="p[id="+b+"]"+"[class='articlePara']";
$(a).something;
});
You have forgotten to pass in event as parameter in your onclick= call in html.
In your javascript, you need to include event in the parenthesis as well.
window.readMore = function(event) {...}
if you write document.getElementById(subID).getElementsByClassName("articlePara"); That's saying you want to get your clicked element's CHILD elements that have class equal to articlePara . There is none. So you get undefined.
If you want to find all element with a ID one and a class articlePara, it can be done easily with jQuery:
newtarget = $("#one.articlePara");
You can insert a line: debugger; in your onclick handler function to trigger the browser's debugging tool and inspect the values of variables. Then you will know whether you are getting what you want.

Get next element with a class name without using jquery

I do not have access to jquery. I'm trying to implement an accordion, but the content element is not immediately after the header. It is something similar to the following:
<div class="header">...</div>
<div>
<div class="content">
So I'm adding a function to handle an onclick event on the header, which needs to then obtain the next element in the HTML source code that has the content class. How can I achieve that?
You can achieve this using querySlector on the clicked header node
<div class="header">
<div>
<div class="content">
[].forEach.call(document.querySelectorAll('.header'), function(header) {
header.addEventListener('click', function(e) {
var content = this.querySelector('.content');
// here, "this" is the header div, and "content" is the content div
// do majick accordion things here
});
});
How about using recursive function and nextSibling [get next element (not children)]
<div class="header" onclick="hasClass(this)">...</div>
<div>
<div class="content"></div>
</div>
<script>
function hasClass(e){
if(e.nextSibling.children === undefined || e.nextSibling.children.length == 0){
hasClass(e.nextSibling); //go next till find class
}
else{
if(e.nextSibling.children[0].className == "content"){
console.log(e.nextSibling.innerHTML); //get class content html
}
}
}
</script>
You can get this by
var contentDiv= document.getElementsByClassName("content");
try this document.getElementById(header).getElementsByClassName('content');

Targeting Multiple Elements with One Function

I have a function that assigns dynamic classes to my div's. This function is a that runs on the page. After the page loads, all 10 of my primary 's have classes ".info1" or ".info2" etc...
I am trying to write a Jquery function that changes the class of the div you click on, and only that one. Here is what I have attempted:
$(".info" + (i ++)).click(function(){
$(".redditPost").toggleClass("show")
});
I have also tried:
$(".info" + (1 + 1)).click(function(){
$(".redditPost").toggleClass("show")
});
And
$(".info" + (i + 1)).click(function(){
$(".redditPost").toggleClass("show")
});
EDITED MY HTML: DIV RedditPost is actually a sibling to Info's parent
<div class="listrow news">
<div class="newscontainer read">
<div class=".info1"></div>
<div class="redditThumbnail"></div>
<div class="articleheader read">
</div>
<div class="redditPost mediumtext"></div>
</div>
My issue is two fold.
The variable selection for ".info" 1 - 10 isn't working because i doesn't have a value.
If I did target the correct element it would change all ".redditPost" classes instead of just targeting the nearest div.
Try like this.
$("[class^='info']").click(funtion(){
$(this).parent().find('.redditPost').toggleClass("show");
});
Alternative:
$('.listrow').each(function(){
var trigger = $(this).find("[class^='info']");
var target = $(this).find('.redditPost');
trigger.click(function(){
target.toggleClass("show");
});
});
Try this
$("div[class*='info']").click(function(){
$(this).parent().find(".redditPost").toggleClass("show")
});
Explanation:
$("div[class*='info'])
Handles click for every div with a class containing the string 'info'
$(this).parent().find(".redditPost")
Gets the redditPost class of the current clicked div
Since the class attribute can have several classes separated by spaces, you want to use the .filter() method with a RegEx to narrow down the element selection as follows:
$('div[class*="info"]').filter(function() {
return /\binfo\d+\b/g.test( $(this).attr('class') );
}).on('click', function() {
$(this).siblings('.redditPost').toggleClass('show');
});
.show {
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="listrow news">
<div class="newscontainer read">
<div class="info1">1</div>
<div class="redditThumbnailinfo">2</div>
<div class="articleheader read">3</div>
<div class="redditPost mediumtext">4</div>
</div>
</div>

Get first child ID from an article with just a class name with Jquery

I have my code like this. It is supposed to show like horizontal buttons with dates. When the user clicks on one of that buttons, the box expands itself showing the pictures in it.
I'm trying to get the first child ID of the article clicked with jquery to be able to show the gallery_items with the first child ID without the "_title" at the end. But I get undefined.
My html:
<section id="gallery">
<article class="gallery_date">
<div id="1389848400_title">16-01-2014</div>
<div class="gallery_items" id="1389848400">
261689_10150238069156283_4353481_n.jpg<br>
IMG_4667.jpg<br>
millenium2.png<br>
</div>
</article>
<article class="gallery_date">
<div id="1389762000_title">15-01-2014</div>
<div class="gallery_items" id="1389762000">
IMG_4661.jpg<br>
</div>
</article>
<article class="gallery_date">
<div id="1389675600_title">14-01-2014</div>
<div class="gallery_items" id="1389675600">
bcn.png<br>
logoenmedio.png<br>
</div>
</article>
</section>
My Jquery:
$().ready(function() {
$(".gallery_date").click(function(event) {
console.log($(".gallery_date:first-child").attr("id"));
});
});
Thanks
"I'm trying to get the first child ID of the article clicked with jquery to be able to show the gallery_items with the first child ID without the "_title" at the end."
Do this:
$(this).children().first().prop("id").split("_")[0];
Or without jQuery so it's not so verbose:
this.children[0].id.split("_")[0];
But if that's the only need for the ID, then you could just select the element with .children() by its class:
$(this).children(".gallery_items")
the first child ID without the "_title".
You can use .replace() to remove '_title' or you can use .split()
$(document).ready(function() {
$(".gallery_date").click(function(event) {
var id = $(this).children().first().attr("id")
console.log(id.replace('_title',''));
console.log(id.split("_")[0]);
});
});
Try this:
$(document).ready(function() {
$(".gallery_date").click(function(event) {
console.log($(this).find('.gallery_items:first-child').attr("id"));
});
});
$(".gallery_date").click(function(event) {
console.log($(this).children().first().attr("id"));
});
If your html is structured the way it is, you can also just use the .next() method to get the gallery_items div, like this, so you don't have to worry about getting IDs and retrieving the DOM elements again:
$(document).ready(function() {
$(".gallery_date").click(function() {
$(this).next(".gallery_items").slideDown();
});
});

How do I use a function argument for this jquery code, or is there a better solution?

I have about 50 p tags and next to these are again 50 divs. on click of each p tag, its div should be shown and the rest hidden. How do i acheive this. I can use something like below:
$(function() {
$('.p1').click(function(){
$('.div1').show();
$('.div2','.div3','.div4','.div5','.div6',.........,'.div50').hide()
})
$('.p2').click(function(){
$('.div2').show();
$('.div1','.div3','.div4','.div5','.div6',.........,'.div50').hide()
})
//////////////
//////
})
but as you see that this is not an effiecient solution. I am also not sure how the jquery each can be leveraged here or how can this implementation be done using arrays. Can somebody point me in the right direction. I think we should use a function and pass that no. as a parameter, but I dont know how to use custom functions in jquery.
UPDATE:
This is what I have done
$(function() {
$('.p1').click(function() {
$('.div').hide();
$('.d1').show();
})
})
I have added the class div to all of my 50 divs and I am showing d1 on click of p1. Now how do I replace 1 for each instance till 50.
I would have a common class to all div and p so that the binding the handler and the hide can be simple. And for the div, I would associate a data-tag to each p to link each p tag to div
<p class="p1 pclass" data-showdiv="div1">
...
</p>
<p class="p2 pclass" data-showdiv="div2">
..
<div class="mydiv div1" ..>
..
</div>
<div class="mydiv div2" ..>
..
</div>
And the script would be,
$(function() {
$('.pclass').click(function(){
$('.mydiv').hide();
$('.' + $(this).data('showdiv')).show();
});
});
As Jason told,
Use this
$('p').click(function() {
$('div').hide();
$(this).next('div').show();
});
If the div is next to each paragraph.
But, if there's an element between p and div, it wont work.
For you problem, you can do,
$('p').click(function() {
$('div').hide();
var divClass = $(this).attr("class").replace('p','div');
$('.' + divClass).show();
});
provided you have only p1, p2 .... in paragrah classes ;)
Update
See this fiddle
Notice , we have <br> tags between <p> and <div> as you wanted.
Assuming your HTML structure is
<p>Some text</p>
<div>More text to hide and show</div>
<p>Some text</p>
<div>More text to hide and show</div>
<p>Some text</p>
<div>More text to hide and show</div>
....
Use the following in your $(function(){}); method:
$('p').click(function() {
$('div').hide();
$(this).next('div').show();
});
var dvs = ['.div1','.div2','.div3','.div4','.div5','.div6',.........,'.div50'];
$('p').click(function() {
var index = parseInt(this.className.replace('p','')) - 1;
$(dvs[index]).show();
$(dvs.join(', ')).not(dvs[index]).hide();
});
The jQuery click event will automatically be registered on all elements that match the selector, so you shouldn't have to use the each() method. I would suggest having two CSS classes to distinguish between elements that have this toggling behaviour and elements that are primary (i.e. should be shown when their parent is clicked).
The markup:
<body>
<p class="togglable">
<div class="primary">
This is the primary div that will be shown when our parent is clicked.
</div>
<div>Regular div child</div>
<p>Nested paragraph</p>
<ul>
<li>A list perhaps</li>
</ul>
</p>
<p class="togglable">
<div class="primary">
This is the primary div that will be shown when our parent is clicked.
</div>
<div>Regular div child</div>
<p>Nested paragraph</p>
<ul>
<li>A list perhaps</li>
</ul>
</p>
<p>This is a normal paragraph</p>
</body>
The code:
$(function () {
$('.togglable').click(function () {
// hide all our children
$(this).children().hide();
// now only show our primary chlid
// NOTE: we pass 'this' as the second argument
// so that the selector will only apply to the
// children of the element that was clicked
// (i.e. we are providing a custom context for the selector).
$('.primary', this).show();
// You could even use the position of the child as well:
// $(this).children().first().show();
// This will show the first child element.
});
});
In this example all elements with the class togglable will show their primary child element when clicked and hide all other child elements.

Categories