I have the HTML as follows. what i need is when someone clicks on the span element i want to find its parents parent element check some conditions. i used prev() method but it gives me only the near parent(parent2 here)
<div class="container">
<div class="contain">
<div id="parent1">
<div class="parent2">
<span> Click here</span>
</div>
</div>
</div>
</div>
var currentComponent = $(event.target).prev(); //here i get parent2
How can i find the parents parent element(in this case parent2). i am not very familiar with jquery so any help would be appreciated.
You can try .closest.
From the docs:
the .closest() method searches through these elements and their ancestors in the DOM tree and constructs a new jQuery object from the matching elements.
(...)
get the first element that matches the selector by testing the element itself and .
It traverses up through the element ancestors in the DOM and returns the first one that matches the selector you passed as an argument. So, in your example, you can do something like that:
$("span").on("click", function(e) {
var myParent = $(this).closest(".parent2");
var parentOfMyParent = $(this).closest(".parent1");
var contain = $(this).closest(".contain");
var containerAbove = $(this).closest(".container");
});
What you need is
var currentComponent = $(event.target).parent().parent()
To do it in a single call, you can use
var currentComponent = $(event.target).closest(".parent1")
Fiddle:
https://jsfiddle.net/c624re4o/
Code:
var grandParent = $(this).parent().parent();
Full Working Code
$(document).ready(function () {
$("span").click(function () {
var grandParent = $(this).parent().parent();
alert(grandParent.attr('id')); // Just for Testing
});
});
$(document).ready(function () {
$("span").click(function () {
var grandParent = $(this).parent().parent();
alert(grandParent.attr('id')); // Just for Testing
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="contain">
<div id="parent1">
<div class="parent2">
<span> Click here</span>
</div>
</div>
</div>
</div>
you can use .closest() or .parents() function with selector like .parents('#elementid')
Related
I am trying to get the index of the clicked element from the MouseEvent object. When I go console click event objects "path" property and hover to first array item it marks actually clicked element.
I wonder how come engine knows which was clicked? Because event.path[0] selector doesn't contain index number of clicked element.
<div id="container">
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
<div>abc</div>
</div>
jsfiddle: https://jsfiddle.net/9n3f7mcr/
You can use Array#indexOf on the children of the parent of event.target, if all the elements you may want the index of have the same parent.
document.addEventListener('click', function (e) {
var target = e.target;
var parent = target.parentNode;
var index = [].indexOf.call(parent.children, target);
console.log("index:", index);
});
<div id="container">
<div>1z</div>
<div>2z</div>
<div>3z</div>
<div>4z</div>
<div>5z</div>
<div>6z</div>
</div>
There are a few ways to go about this depending on how you want to use the index of each child element. I think using data attributes is generally a good approach:
HTML
<div id="container">
<div data-id="1">1z</div>
<div data-id="2">2z</div>
<div data-id="3">3z</div>
<div data-id="4">4z</div>
<div data-id="5">5z</div>
<div data-id="6">6z</div>
</div>
JS
const container = document.getElementById("container");
function handleClick(evt) {
const childNode = evt.target.closest("div");
console.log(childNode.dataset.id);
}
container.addEventListener("click", handleClick, false);
I have a parent div with some child elements. I want to re-order child elements based on two id values. for example 1,4. It means to grab the item with id 1 and insert it above the item with id 4.
<div class="parent">
<div id="1">First</div>
<div id="2">Second</div>
<div id="3">Third</div>
<div id="4">Fourth</div>
<div id="5">Fifth</div>
</div>
Making a drag and drop component for react. And this is what i have tried
const element = document.getElementById('1') //dragStart
const targetElement = document.getElementById('4') //dragEnter
const parent = document.querySelector('.parent') // drop
parent.insertBefore(element, targetElement)
But problem is when i grab the first element and want to put it on the bottom (last child). It fails to do so. How to put a child element after last child with insertBefore() method?
Don't know how you are using insertBefore() but there should not be any issues:
Update: The issue could be that your code is running before the DOM is fully loaded. You can wrap your code with DOMContentLoaded:
<script>
document.addEventListener('DOMContentLoaded', (event) => {
const element = document.getElementById('1') //dragStart
const targetElement = document.getElementById('4') //dragEnter
const parent = document.querySelector('.parent') // drop
parent.insertBefore(element, targetElement)
});
</script>
<div class="parent">
<div id="1">First</div>
<div id="2">Second</div>
<div id="3">Third</div>
<div id="4">Fourth</div>
<div id="5">Fifth</div>
</div>
Placing the first element as the last element using nextSibling:
<script>
document.addEventListener('DOMContentLoaded', (event) => {
const parentNode = document.querySelector('.parent');
const element = document.getElementById('1') //dragStart
const targetElement = document.querySelector('.parent').lastElementChild //get last child
parentNode.insertBefore(element, targetElement.nextSibling);
});
</script>
<div class="parent">
<div id="1">First</div>
<div id="2">Second</div>
<div id="3">Third</div>
<div id="4">Fourth</div>
<div id="5">Fifth</div>
</div>
Note: This answers the original question. The question has now been edited to reference React. You wouldn't use the following in a React project. You'd reorder the state that the DOM represents, and then let React handle updating the DOM.
You're right to use insertBefore:
function moveElement(move, before) {
// Get the element to move
const elToMove = document.getElementById(move);
// Get the element to put it in front of
const elBefore = document.getElementById(before);
// Move it
elBefore.parentNode.insertBefore(elToMove, elBefore);
}
function moveElement(move, before) {
const elToMove = document.getElementById(move);
const elBefore = document.getElementById(before);
elBefore.parentNode.insertBefore(elToMove, elBefore);
}
setTimeout(() => {
moveElement("1", "4");
}, 800);
<div class="parent">
<div id="1">First</div>
<div id="2">Second</div>
<div id="3">Third</div>
<div id="4">Fourth</div>
<div id="5">Fifth</div>
</div>
Side note: I suggest avoiding having id values that start with digits. Although they're perfectly valid HTML and they work just fine with getElementById, they're a pain if you need to target them with CSS, because a CSS ID selector (#example) can't start with an unescaped digit. For instance, document.querySelector("#1") fails. You have to escape the 1 with a hex sequence, which isn't terrifically clear: document.querySelector("#\\31") (the characters \, 3, and 1: 0x31 = 49 = the Unicode code point for 1).
I have HTML:
<footer class="footer">
<div class="container-fluid wrapper">
...
</div>
</footer>
How do I remove the whole footer markup using javascript (no jQuery available)?
I've tried:
var elem = document.getElementsByName("footer");
elem.remove();
...and a couple of other variations, but I can't get it to delete.
Any ideas?
Thanks, Mark
Yes, you can do like this
function removeTagByTagName(tagName) {
var ele = document.getElementsByTagName(tagName);
return ele[0].parentNode.removeChild(ele[0]);
}
function removeTag(tag) {
var ele = document.getElementsByTagName(tag);
return ele[0].parentNode.removeChild(ele[0]);
}
var btn = document.getElementById("delet");
btn.addEventListener("click", function(){
removeTagByTagName("footer");
});
<body>
<button id="delet">Delete Footer!</button>
<footer class="footer" name="footer">
<div class="container-fluid wrapper">
blab bal babla
</div>
</footer>
</body>
you cannot use .remove with all browsers, since the support is not that good yet. I would recommend polyfilling the remove, so that you can use this. Use the following polyfill (taken from MDN):
// from:https://github.com/jserz/js_piece/blob/master/DOM/ChildNode/remove()/remove().md
(function (arr) {
arr.forEach(function (item) {
if (item.hasOwnProperty('remove')) {
return;
}
Object.defineProperty(item, 'remove', {
configurable: true,
enumerable: true,
writable: true,
value: function remove() {
this.parentNode.removeChild(this);
}
});
});
})([Element.prototype, CharacterData.prototype, DocumentType.prototype]);
Now you can use .remove() with ease.
You can also use .removeChild() if you know the parent of the node you want to delete. Something like this:
var parent = document.getElementById("div1");
var child = document.getElementById("p1");
parent.removeChild(child);
So since your is inside the , you can treat the body as the parent and remove its child () using similar code as above snippet.
You would need to grab that specific footer element. What you have with var elem = document.getElementsByName("footer"); grabs a collection of all elements named "footer" but if you want to do it that way, you need to add the name="footer" attribute to your footer element. The way your HTML is set up right now, you could change that line to:
var elem = document.getElementsByTagName("footer");
If you only have one footer element, then you can target that one like this:
var elem = document.getElementsByTagName("footer")[0];
Otherwise, you could assign that element an ID, or figure out which footer item in the collection it was (i.e. document.getElementsByTagName("footer")[3]).
Once you have that specific element, you can remove it like this:
elem.parentNode.removeChild(elem);
The removeChild function and querySelector can be used to fulfil your needs.
function remove(){
var el=document.querySelector('footer.footer');
el.parentNode.removeChild(el);
}
remove();
<footer class="footer">
<div class="container-fluid wrapper">
...
</div>
</footer>
I have the following code:
.recipe
.ingredients
= f.simple_fields_for :ingredients do |ingredient|
= render 'ingredient_fields', f: ingredient
.row#links
.col-xs-12
= link_to_add_association "", f, :ingredients
%hr
I need to select the ingredients div using jquery in the format of $("#links")["closest"](".recipe > .ingredients") but this doesn't select anything.
It's frustrating though as $("#links")["closest"](".recipe > .row") will return the correct div.
Fiddle of what works and what I want: https://jsfiddle.net/yL6dr4s1/
According to jQuery documentation, closest method tries to find element matching the selector by testing the element itself and
traversing up through DOM.
It does not go through siblings of the element.
Based on your requirements, it seems like you want to traverse the tree for getting match in siblings. jQuery has siblings method to do that. So one solution would be to use siblings method like:
$("#links")["siblings"](".recipe > .ingredients")
Another soultion would be to get closest parent and then use children as answered by #mhodges
As for the query $("#links")["closest"](".recipe > .row"):
It works fine because closest method finds the match in the element itself.
Here is the example to showcase that:
$(document).ready(function() {
// Match found because it is parent
console.log($("#links")["closest"](".wrapper").length);
// No match found because element is sibling
console.log($("#links")["closest"](".row1").length);
// No match found because element is sibling
console.log($("#links")["closest"](".row3").length);
// Match found because it is element itself
console.log($("#links")["closest"](".row2").length);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="row1">
<span>Content1</span>
</div>
<div class="row2" id="links">
<span>Content2</span>
</div>
<div class="row3">
<span>Content3</span>
</div>
</div>
I am not sure of your requirements on using the exact selector/syntax you provided, but this selector works exactly how you want it to.
$(this).closest(".recipe").children(".ingredients").append('<br/><input type="text" value="Flour">');
Edit
This is the closest I could get:
$(this)["closest"](".recipe").children(".ingredients").append('<br/><input type="text" value="Flour">');
I don't think you can use the selectors in the way you propose.
As far as the DOM is concerned (and jQuery), the element defined by ingredient and the element defined by row are not related. You have to traverse up to the parent element, then back down to get to the child.
Here is a fiddle that hopefully demonstrates the issue.
If you can change it so that ingredient and row are both within the same parent div, you might have more luck with your test selector syntax.
When jQuery gets to buggy, doesn't have a certain option or just becomes to messy to use for a certain operation, it is good we also have access to good old plain javascript.
document.querySelector('#addToIngredients').addEventListener('click' , function(e) {
var recipe = getClosest(e.target,'recipe');
if (recipe) {
var ingred = recipe.querySelector('.ingredients');
ingred.innerHTML += '<br/><input type="text" value="Flour">';
}
});
function getClosest(elem,cls) {
var el = elem.parentNode;
while (el){
if (el.className.indexOf(cls) > -1) {
return el;
}
el = el.parentNode;
}
return false;
}
<div class="recipe">
<div class="ingredients">
<input type="text" value="Eggs"><br/>
<input type="text" value="Flour">
</div>
<div class="row">
<div class="col-xs-12">
Add to .ingredients
</div>
</div>
<hr/>
</div>
Of course they can be combined
$(function() {
$("#addToIngredients").on('click', function(e) {
var recipe = getClosest(e.target,'recipe');
if (recipe) {
var ingred = recipe.querySelector('.ingredients');
ingred.innerHTML += '<br/><input type="text" value="Flour">';
}
});
})
Is there a jQuery selector that will grab all elements of class A that are not descendants of class B?
Example:
<body>
<div class=report-value id=overview></div>
<div class=panels>
<div class=report-value id=sales></div>
<div class=report-value id=training></div>
<div class=report-value id=hr></div>
</div>
<div class=report-value id=summary></div>
</body>
For the above example, the need is to select all .report-value elements that are not descendants of the .panels element. The report values are computationally heavy and need to be calculated only when actually displayed.
Something like:
var elems = $('.report-value:excludeTree(.panels)');
which would return a jQuery object containing only #overview and #summary.
Performance is important for this web application.
You can use .not() filter out those elements
$('.report-value').not('.panels .report-value')
Demo: Fiddle
Try,
var elems = $('.report-value').filter(function(){
return $(this).closest('.panels').length ==0;
});
DEMO
var allpanels=$('body>.report-value');
$('body > .report-value')
or
$('.report-value').each(function(){
if(!$(this).parent().hasClass('.panels'))
{
//use query
}
});
Try this:
$('.report-value').each(function(){
if(!$(this).parent().hasClass('panels') && !$(this).parents().eq(1).hasClass('panels'))
{
console.log($(this));
}
});
It console only ur required divs