I have a container that opens via an onclick function. I then have a cross within the container that should close the parent element however I receive a
TypeError: undefined is not an object (evaluating 'parent.id')
Code is here
<div class="post" onclick="postClick(el)">
...
...
</div>
JavaScript
function postClick(el) {
document.getElementById(el.id).classList.add("read");
}
function postClose(event) {
var parent = this.parentNode;
console.log(parent.id);
parent.id.classList.remove("read");
}
Use event.target to get the reference to the HTML element.
And you have an extra .id in the parent.id.classList expression.
function postClick(event) {
const el = event.target;
document.getElementById(el.id).classList.add("read");
}
function postClose(event) {
const el = event.target;
const parent = el.parentNode;
console.log(parent.id);
parent.classList.remove("read");
}
<div class="post" onclick="postClick(event)">
...
...
</div>
One way of doing this is using pure Javascript and bind the event listener like this
document.querySelector('#toggle').addEventListener('click', function (e) {
console.log(this.parentNode.classList.remove('read'))
});
div {
padding: 20px 50px;
}
div.read {
background-color: red;
}
<div class="read">
<button id="toggle">Remove Parent Class</button>
</div>
Jut use this and you are done : 😊
element.parentNode.classList.remove("class-name");
if the project is complex and needs interactivity more than often then you use jquery library for the interactivity.
//to remove class
$( "p" ).removeClass( "myClass yourClass" )
$("#div123").toggle(); //if you want to temp hide elements
as your code suggests the 'read' items must be disabled, you can toggle them once an event handler is wrapped over the toggle method. you can pass this or $(this) in case you want to do stuff with the owner of the function call.
well i agree some adept devs didnt like this answer, it will be surely of some help to some beginner dev in future who is looking for an alternative option to hide elements or remove classes
Related
How do I get the clicked div if the divs both got same class.
For an example:
<div class="box"></div> <div class="box"></div>
And I want to add another class to the div I click on.
New at JavaScript but I have figured out that I should use "this" in some way.
What I have done so far:
box = document.getElementById("box");
box.addEventListener("click, function(event) {
event.target.classList.toggle("clicked");
}
But of course this only works for a div with an Id and not for multiple divs.
You can use document.querySelectorAll here like:
var boxes = document.querySelectorAll('.box');
Array.from(boxes).forEach(box => {
box.addEventListener('click', function(e) {
e.target.classList.toggle('clicked');
});
});
If you want to use document.getElementById() you need to add element the id attribute:
<div id="box1" class="box">
By design, ids are meant to be unique, so if you can assign each element an id, it shoud be enough.
I'd suggest an approach where you add the listener on a parent (or whole document) and check for the clicked element inside:
document.addEventListener('click', function (event) {
if(event.target.classList.contains('box')) {
event.target.classList.toggle('clicked');
}
}
This approach is better performance-wise as it creates only one event handler, not a handler per element.
with jquery
$('.box').click(function() {
console.log($(this).text());
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">one</div><div class="box">two</div>
If you want to keep using pure JavaScript without any additional lib, I believe Query Selectores should help you (https://developer.mozilla.org/pt-BR/docs/Web/API/Element/querySelectorAll).
Evolving your snippet:
document.querySelectorAll("box").forEach( function (){
this.addEventListener('click', function(event) {
event.target.classList.toggle("clicked");
});
});
If you attach the eventListener onto a containing element, here I've just used body, but more targeted selectors can give better performance.
You could then check the class of the item clicked.
Example below..
document.body.addEventListener("click", function (evt) {
var el = evt.srcElement;
if (el.classList.contains("box"))
el.classList.toggle("clicked");
});
.clicked {
background-color: yellow;
}
<div class="box">Box 1</div>
<div class="notabox">Not a Box</div>
<div class="box">Box 2</div>
I have the following html (it's a card) where a class is added to change the look of it:
<div class="card-small-half" id="card-1">
<a href="components/">
<div class="action-bar">
<p>Add Page</p>
<i class="material-icons">add</i>
</div>
</a>
</div>
and a switch made with a label that checks and unchecks an input type checkbox:
<div class="switch-wrapper" id="switch-wrapper-1">
<input type="checkbox" id="input-1" class="display-none">
<label class="switch" for="input-1"></label>
<p id="switch-caption-1">Visible</p>
</div>
With the following Javascript I add a class called "card-disabled" to the card:
window.onload = function () {
function check() {
if (document.getElementById("input-1").checked) {
document.getElementById("switch-caption-1").textContent = "Disabled";
$('#card-1').addClass('card-disabled');
} else {
document.getElementById("switch-caption-1").textContent = "Visible";
$('#card-1').removeClass('card-disabled');
}
}
document.getElementById('input-1').onchange = check;
check();
}
I know in css you can call id's or classes like so:
#switch-wrapper-1 input { /* styles */ }
or
#switch-wrapper-1 p { /* styles */ }
How can I do this with javascript, so I don't have to use an id for every element and instead use a global id for every wrapper.
EDIT:
The wrapper and input id's are unique! I want to call the paragraph inside the unique wrapper element something like this:
document.getElementById("switch-wrapper-1 p").textContent = "Disabled";
The 'p' here means paragraph
Is this possible and if so: how?
Query Selector is your friend here. You can use CSS selectors to retrieve DOM elements. In your case this call would return the first paragraph child in the #switch-wrapper-1 element.
var node = document.querySelector('#switch-wrapper-1 p');
If you also use jQuery, then as suggested in comments, you can simply use the $ function.
var $node = $('#switch-wrapper-1 p');
To select an individual element inside of an element with a specific ID using Javascript you can do:
document.getElementById('hello').getElementsByTagName('input')[0];
So in your example it would be:
document.getElementById('switch-wrapper-1').getElementsByTagName('input')[0].onchange = check;
The [0] is used because getElementsByTagName returns an array of all the child elements inside the parent element with the specified tag. Note that you will have to keep the unique ID on the input field if you want the for attribute on the label to function correctly.
I have two IDs in same name ! if any one clicked among them , i need to change the class name of the both IDs. i know we should use ID for single use. Because of my situation(I have two classes for button ) so i have moved to ID.
Her is my code if i click one id that name only changes another one is remains same
<button class="success" id="1" onClick="reply(this.id)"> Added </button>
<button class="success" id="1" onClick="reply(this.id)"> Added </button>
js function
function reply(clicked_id)
{
document.getElementById(clicked_id).setAttribute('class', 'failed');
var el = document.getElementById(clicked_id);
if (el.firstChild.data == "Added")
{
el.firstChild.data = "Add";
}
}
if i use instead of 'class' to id while renaming class which one will be renamed success class or 'class name 1' ?
You can't. Getelementbyid will only return one element. Probably the first one.
Pure JS Is Second Example
My JS Fiddle Example: http://jsfiddle.net/eunzs7rz/
This example will use the class attribute only to perform the switching that you need, its a extremely basic example as do not want to go beyond what is needed... Also i forgot to remove the id's in the JS Fiddle Example.. so just ignore them
THE CSS:
.success {
background-color:#00f;
}
.failed {
background-color:#f00;
}
THE HTML:
<button class="success"> Added </button>
<button class="success"> Added </button>
THE JAVSCRIPT:
$(function() {
$(".success").click(function(){
Reply(this);
});
});
function Reply(oElm) {
$(oElm).attr('class', 'failed');
}
EDIT - PURE JAVASCRIPT VERSION
Sorry, did not think to check the post tags if this was pure JS. But here you go anyway ;)
<style>
.success {
background-color:#00f;
}
.failed {
background-color:#f00;
}
</style>
<button class="success" onclick="Reply(this)"> Added </button>
<button class="success" onclick="Reply(this)"> Added </button>
<script>
function Reply(oElm) {
oElm.className = 'failed';
}
</script>
THE MAIN THING HERE
Once you have the element either by using 'this' or by using 'getElementBy', you can then simply use ".className" to adjust the class attribute of the selected element.
As already explained by others, id is for single use and is quicker than using class or type. So even if you have a group, if only one is ever used.. use an id.
Then you use the object/reference of 'this' from an event on an element, in this case the onclick... that will send that variable to the function / code called.
So using 'this' is a preferred option as it will always reference the element that it is used/called from.
pass elemenet, not it's Id
<button class="success" id="1" onClick="reply(this)"> Added </button>
<button class="success" id="1" onClick="reply(this)"> Added </button>
function reply(elem)
{
$(elem).setAttribute('class', 'failed');
if (elem.firstChild.data == "Added")
{
elem.firstChild.data = "Add";
}
}
the ID attribute must be unique or else it will get the last defined element with that ID.
See this for reference.
Use a class instead of an id. ids are supposed to be unique in a dom tree.
html:
<button class="success" onClick="reply()"> Added </button>
<button class="success" onClick="reply()"> Added </button>
js:
var ary_success = document.querySelectorAll(".success"); // once and forever. If the set of elements changes, move into function `reply`
function reply () {
var elem;
var s_myclasses;
for (var i=0; i < ary_success.length; i++) {
elem = ary_success[i];
s_myclasses = elem.getAttribute('class');
s_myclasses = s_myclasses.replace ( /(success|failed)/g, '' );
s_myclasses = s_myclasses + ' failed';
elem.setAttribute('class', s_myclasses );
if ( elem.firstChild.data.indexOf("Added") !== -1) {
elem.firstChild.data = "Add";
}
}
}
Live Demo here.
Notes
Make sure that you set ary_successin the onload handler or in an appropriately placed script section - at the timeof execution the buttons must be present in the dom ! If in doubt, move it to the start of reply' body.
If you employ jquery, the code simplifies (well...) to:
$(document).ready( function () {
$(".success").on ( 'click', function ( eve ) {
$(".success").removeClass("success").addClass("failed");
$(".success *:first-child:contains('Added')").text(" Add ");
});
});
Updates
Notes, Live Demo
Iterator method changed, every not supported on test platform
What I'd like to do is have all elements of class collapsible_list not displayed by default (with one exception... see below*), and then toggle their display when their parent <div class="tab_box"> is clicked. During the same click, I'd also like for every other element of class collapsible_list to be hidden so that only one of them is expanded at any given time.
*Furthermore, when the page initially loads I'd also like to check to see if an element of collapsible_list has a child a element whose class is activelink, and if there is one then I'd like that link's parent collapsible_list element to be the one that's expanded by default.
Here's some sample html code:
<style>
.collapsible_list {
display: none;
}
.collapsible_list.active {
display: block;
}
</style>
<div id="sidebar">
<div class="tab_box">
<div class="collapsible_tab">2014</div>
<div class="collapsible_list panel-2014">
1
2
3
</div>
</div>
<div class="tab_box">
<div class="collapsible_tab">2013</div>
<div class="collapsible_list panel-2013">
<a class="activelink" href="/2013/1">1</a>
2
3
</div>
</div>
</div>
And here's where I'm currently at with the javascript (although I've tried a bunch of different ways and none have worked like I'd like them to):
$(document).ready(function() {
// This looks redundant to me but I'm not sure how else to go about it.
$(".collapsible_list").children("a.activelink").parent(".collapsible_list:not(.active)").addClass("active");
$(".tab_box").click(function() {
$(this).children(".collapsible_list").toggleClass("active").slideToggle("slow", function() {
$(".collapsible_list.active:not(this)").each(function() {
$(this).slideToggle("slow");
});
});
});
});
I hope that's not too confusing, but if it is then feel free to let me know. Any help is much appreciated.
Since you have a dom element reference that needs to be excluded use .not() instead of the :not() selector
jQuery(function ($) {
// This looks redundant to me but I'm not sure how else to go about it.
$(".collapsible_list").children("a.activelink").parent(".collapsible_list:not(.active)").addClass("active").show();
$(".tab_box").click(function () {
var $target = $(this).children(".collapsible_list").toggleClass("active").stop(true).slideToggle("slow");
//slidup others
$(".collapsible_list.active").not($target).stop(true).slideUp("slow").removeClass('active');
});
});
Also, instead of using the slide callback do it directly in the callback so that both the animations can run simultaniously
Also remove the css rule .collapsible_list.active as the display is controlled by animations(slide)
Try This.
$('.collapsible_tab a').on('click', function(e){
e.preventDefault();
$('.collapsible_list').removeClass('active')
$(this).parent().next('.collapsible_list').toggleClass('active');
});
Fiddle Demo
I think your code would be less complicated if you simply remembered the previously opened list:
jQuery(function($) {
// remember current list and make it visible
var $current = $('.collapsible_list:has(.activelink)').show();
$(".tab_box").on('click', function() {
var $previous = $current;
// open new list
$current = $('.collapsible_list', this)
.slideToggle("slow", function() {
// and slide out the previous
$previous.slideToggle('slow');
});
});
});
Demo
I have the following code.
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
</head>
<div id="hello">Hello <div>Child-Of-Hello</div></div>
<br />
<div id="goodbye">Goodbye <div>Child-Of-Goodbye</div></div>
<script type="text/javascript">
<!--
function fun(evt) {
var target = $(evt.target);
if ($('div#hello').parents(target).length) {
alert('Your clicked element is having div#hello as parent');
}
}
$(document).bind('click', fun);
-->
</script>
</html>
I expect only when Child-Of-Hello being clicked, $('div#hello').parents(target).length will return >0.
However, it just happen whenever I click on anywhere.
Is there something wrong with my code?
If you are only interested in the direct parent, and not other ancestors, you can just use parent(), and give it the selector, as in target.parent('div#hello').
Example: http://jsfiddle.net/6BX9n/
function fun(evt) {
var target = $(evt.target);
if (target.parent('div#hello').length) {
alert('Your clicked element is having div#hello as parent');
}
}
Or if you want to check to see if there are any ancestors that match, then use .parents().
Example: http://jsfiddle.net/6BX9n/1/
function fun(evt) {
var target = $(evt.target);
if (target.parents('div#hello').length) {
alert('Your clicked element is having div#hello as parent');
}
}
.has() seems to be designed for this purpose. Since it returns a jQuery object, you have to test for .length as well:
if ($('div#hello').has(target).length) {
alert('Target is a child of #hello');
}
Vanilla 1-liner for IE8+:
parent !== child && parent.contains(child);
Here, how it works:
function contains(parent, child) {
return parent !== child && parent.contains(child);
}
var parentEl = document.querySelector('#parent'),
childEl = document.querySelector('#child')
if (contains(parentEl, childEl)) {
document.querySelector('#result').innerText = 'I confirm, that child is within parent el';
}
if (!contains(childEl, parentEl)) {
document.querySelector('#result').innerText += ' and parent is not within child';
}
<div id="parent">
<div>
<table>
<tr>
<td><span id="child"></span></td>
</tr>
</table>
</div>
</div>
<div id="result"></div>
If you have an element that does not have a specific selector and you still want to check if it is a descendant of another element, you can use jQuery.contains()
jQuery.contains( container, contained )
Description: Check to see if a DOM element is a descendant of another DOM element.
You can pass the parent element and the element that you want to check to that function and it returns if the latter is a descendant of the first.
Ended up using .closest() instead.
$(document).on("click", function (event) {
if($(event.target).closest(".CustomControllerMainDiv").length == 1)
alert('element is a child of the custom controller')
});
You can get your code to work by just swapping the two terms:
if ($(target).parents('div#hello').length) {
You had the child and parent round the wrong way.
Without jquery
target.matches() with :scope
If you want to see if the target element has a parent which matches some selector use the .matches() method on the target and pass the selector followed by the :scope pseudo class.
The :scope here refers to the target element so you can use the in a :where pseudo class to help you write out a clean selector.
In the following example we will match all target elements which are a decedent of an a, button, or summary element.
const app = document.getElementById("app");
app.addEventListener("click", (event) => {
if (
event.target.matches(
":where(a, button, summary) :scope"
)
) {
console.log("click", event.target.parentNode.tagName);
}
});
<div id="app">
<button>
<span>Click Me</span>
</button>
<a href="#">
<span>Click Me</span>
</a>
<details>
<summary>
<span>Click Me</span>
</summary>
</details>
<span>Click Me</span>
<div>
Note the selector :where(a, button, summary) :scope could also have been written as:
a :scope,
button :scope,
summary :scope
parent.contains()
If you are interested in seeing if the target element is a child of a specific element use .contains() on the potential parent element:
const app = document.getElementById("app");
const button = document.getElementById("button");
app.addEventListener("click", (event) => {
if (button.contains(event.target)) {
console.log("click");
}
});
<div id="app">
<button id="button">
<span>Click Me</span>
</button>
<span>Click Me</span>
<div>
In addition to the other answers, you can use this less-known method to grab elements of a certain parent like so,
$('child', 'parent');
In your case, that would be
if ($(event.target, 'div#hello')[0]) console.log(`${event.target.tagName} is an offspring of div#hello`);
Note the use of commas between the child and parent and their separate quotation marks. If they were surrounded by the same quotes
$('child, parent');
you'd have an object containing both objects, regardless of whether they exist in their document trees.
To know more background info on Aleksandr Makov's answer, checking the below page might be helpful.
https://developer.mozilla.org/en-US/docs/Web/API/Node/contains
Node.contains()
The contains() method of the Node interface returns a boolean value indicating whether a node is a descendant of a given node, that is the node itself, one of its direct children (childNodes), one of the children's direct children, and so on.
It means, the answer is not using a reclusive function.