How to traverse the DOM to get to specific element - javascript

I'm having a brain freeze trying to remember what the best way is to access the data attribute on an anchor tag when clicking a button that's not inside the tags container, could someone assist me on how I would do this, so if I click .js-watchlist-add I want to get the data-id of .js-film-entry:
JS
<div class="ctn">
<a href="/movie/{{id}}" class="film-entry js-film-entry" data-id="{{id}}">
<img src="{{poster}}" class="film-img">
<div class="result-film-details">
<h2 class="film-title">{{title}}</h2>
<p class="film-release-date">Released {{releaseYear}}</p>
<ul class="result-stats-tabs clearfix">
<li>{{vote_average}} <span>Vote Average</span></li>
<li>{{vote_count}} <span>Vote Count</span></li>
</ul>
</div>
</a>
<div class="cta-ctn">
<button class="watchlist-add js-watchlist-add">Add to watchlist</button>
<button class="watchlist-remove js-watchlist-remove">Remove from watchlist</button>
</div>
</div>

You can use closest() to get the parent element and find() to get the descendant within parent.
Live Demo
$(this).closest('.ctn').find('.js-film-entry').data('id');

You can use jQuery's has and find methods.
$('.ctn').has(this).find('.js-film-entry')

Adil's answer is great,
Though it may be more efficient to use children versus find, to avoid traversing descendants.
$(this).closest('.ctn').children('.js-film-entry').data('id');
Just to give another DOM traversal example, you could also use:
$(this).parent().siblings('.js-film-entry').data('id');

Related

How can I get a Node's only direct children with a specific class name?

How can I get a Node's only direct children with a specific class name?
Example
<div class="list-group">
<div class="list-group-item">
<div class="list-group"> <!--I have this-->
<div class="list-group-item"> <!--And I want to reach this-->
<div class="list-group">
<div class="list-group-item"></div> <!--Not this-->
<div class="list-group-item"></div>
</div>
</div>
<div class="list-group-item"></div> <!--And get this-->
</div>
</div>
</div>
I have a list-group that contains items and groups and I want to keep that hierarchy and get a list-group's only direct list-group-items.
How can I do so?
You haven't mentioned if you use any JS frameworks, but with JQuery it is fairly simple... just use children()
In example $("#haveThis").children()
You can also filter children like: $("#haveThis").children("list-group-item")
docs: https://api.jquery.com/children/
For vanilla JS I'd do this:
[].slice.call(document.getElementById("havethis").children).filter(el=>el.className==='list-group-item')
In vanilla JS (if you're not using jQuery) element.children (where element is the parent you wish to query) will return a list of all direct child nodes, you would then itterate over the list list, looking for node.className = "list-group-item";
I've not found a way to do this with standard CSS selectors, so a coded solution seems to be the only option.
Get all elements with the specified class name:
var x = document.getElementsByClassName("list-group-item");
Link https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName

How to get a div which is removed from the DOM when it's parent has been made .empty()?

I have a div in a HTML file
"<div id="abc" hidden="hidden">
<div id="statIndicator">
<span id="imgInd" class="status-indicator-border">
<img src="../../LibSrc/SharedResources/IMG/loading-trace.gif" />
</span><span id="messageIndicator">Updating Plots...</span>
</div>
</div>"
I insert the statIndicator div in another div using append.
so that div becomes
<div id="parentDiv">
<div id="statIndicator">
<span id="imgInd" class="status-indicator-border">
<img src="../../LibSrc/SharedResources/IMG/loading-trace.gif" />
</span><span id="messageIndicator">Updating Plots...</span>
</div>
</div>
On refresh I write $('#parentDiv').empty() it deletes whatever is inside the 'parentDiv'.
But when I try to append statIndicator using $('#statIndicator'), it return "[]", though I have the 'statIndicator' div in Html.
Is there a way in which I can get the 'statIndicator' div?
No. $.empty() deletes the contents, so your "statIndicator" div no longer exists at all.
Just remove it from "parentDiv" before you call $.empty(). Either store it in a variable or put it back where it started, in "abc".
I think jquery.append() moves the selected elements without making a copy. So you can explicitly create a copy using the .clone() method and append it's result. Something like:
$('#abc #statIndicator').clone().appendTo('#parentDiv');
This is creating a copy and then appending it at the new location.
Once you do this there will be two divs with the same id, so it will be a good idea to always reference the statIndicator's parent container in your selectors.
You can use .detach() function if you want only parentDiv to be removed

Easiest way to get element parent

Suppose i have this structure of elements:
<div class="parent">
<div class="something1">
<div class="something2">
<div class="something3">
<div class="something4"></div>
</div>
</div>
</div>
</div>
And code like this:
$(".something4").click(function(){
//i could do it like this...
$(this).parent().parent().parent().parent().parent();
});
But that seems to be stupid, is there a better way to do this?
also i can't just say $(.parent) because there are many divs like this with class parent in my page.
Use .closest(selector). This gets the first element that matches the selector, beginning at the current element and progressing up through the DOM tree.
$('.something4').click(function() {
$(this).closest('.parent');
});
Use .closest():
$('.something4').click(function() {
$(this).closest('.parent');
});
I think you should try this
$(this).parents(".parent");
But I don't know where on the page are the other divs with this class :)
You could always use .parentNode (standard JavaScript). It's generally a bad idea to use class names that coincide with function/variable names from the library you're using (this goes for any language). Making your class names more unique is a better approach (for instance, "scparent" instead of "parent", if the name of your application was "Super Calculator" or something). This avoids conflicts such as the one you're describing.
I would caution using .closest(), simply because you may create a function like this:
function getParentElem() {
return $(this).closest('div');
}
And it would grab the parent div's in your code just fine, but if down the road you add a table for displaying data, and you run the function through a child element of the table, you will have to create another implementation that selects the table element, because that's what you now want:
<div id="tableParent">
<table id="dataTable">
<tr id="target1">
<td>Some data.</td>
</tr>
</table>
</div>
By using your function getParentElem() on the tr element, you'll end up grabbing the div with id="tableParent", rather than the actual parent, which is the table element. So, unless you've delineated your parent classes appropriately all the way through your code (which can be a pain and isn't always efficient), you may run into problems. Especially if at any point you're creating elements programmatically, or reading in data from another 3rd-party library or script.
Not saying it's not good to use .closest()... just pointing out a possible "gotcha".
i would suggest adding to the div parent an id like 'parent_1' etc. and in every son you keep the id in the rel attr
<div id="parent_1" class="parent">
<div rel="1" class="something1">
<div rel="1" class="something2">
<div rel="1" class="something3">
<div rel="1" class="something4"></div>
</div>
</div>
</div>
</div>
$(".something4").click(function(){
//i could do it like this...
$('#parent_' + $(this).attr('rel'));
});

How to delete parent element using jQuery

I have some list item tags in my jsp. Each list item has some elements inside, including a link ("a" tag) called delete. All that I want is to delete the entire list item when I click the link.
Here is the structure of my code:
$("a").click(function(event) {
event.preventDefault();
$(this).parent('.li').remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li id="191" class="li">
<div class="text">Some text</div>
<h4>Text</h4>
<div class="details">
<img src="URL_image.jpg">
<span class="author">Some info</span>
<div class="info"> Text
<div class="msg-modification" display="inline" align="right">
<a name="delete" id="191" href="#">Delete</a>
</div>
</div>
</div>
</li>
But this doesn't work. I'm new at jQuery, so I tried some things, like for example:
$(this).remove();
This works, it deletes the link when clicked.
$("#221").remove();
This works, it deletes the indicated list item, but it's not "dynamic".
Can someone give me a tip?
Simply use the .closest() method: $(this).closest('.li').remove();
It starts with the current element and then climbs up the chain looking for a matching element and stops as soon as it found one.
.parent() only accesses the direct parent of the element, i.e. div.msg-modification which does not match .li. So it never reaches the element you are looking for.
Another solution besides .closest() (which checks the current element and then climbs up the chain) would be using .parents() - however, this would have the caveat that it does not stop as soon as it finds a matching element (and it doesn't check the current element but only parent elements). In your case it doesn't really matter but for what you are trying to do .closest() is the most appropriate method.
Another important thing:
NEVER use the same ID for more than one element. It's not allowed and causes very hard-to-debug problems. Remove the id="191" from the link and, if you need to access the ID in the click handler, use $(this).closest('.li').attr('id'). Actually it would be even cleaner if you used data-id="123" and then .data('id') instead of .attr('id') to access it (so your element ID does not need to resemble whatever ID the (database?) row has)
what about using unwrap()
<div class="parent">
<p class="child">
</p>
</div>
after using - $(".child").unwrap() - it will be;
<p class="child">
</p>
Use parents() instead of parent():
$("a").click(function(event) {
event.preventDefault();
$(this).parents('.li').remove();
});
Delete parent:
$(document).on("click", ".remove", function() {
$(this).parent().remove();
});
Delete all parents:
$(document).on("click", ".remove", function() {
$(this).parents().remove();
});
I have stumbled upon this problem for one hour. After an hour, I tried debugging and this helped:
$('.list').on('click', 'span', (e) => {
$(e.target).parent().remove();
});
HTML:
<ul class="list">
<li class="task">some text<span>X</span></li>
<li class="task">some text<span>X</span></li>
<li class="task">some text<span>X</span></li>
<li class="task">some text<span>X</span></li>
<li class="task">some text<span>X</span></li>
</ul>
You could also use this:
$(this)[0].parentNode.remove();
$('#' + catId).parent().remove('.subcatBtns');

(Javascript) Inserting elements dynamically in a specific position

Basically what I have is this:
<body>
<div class="class1">
</div>
<div class="class2">
</div>
<div class="class3">
</div>
...
</body>
I have no idea why the site creator used classes instead of IDs (they're unique), but it doesn't really matter as I'm writing a GM script and so getElementsByClassName('')[0] effectively does the same thing.
How can I insert an element between the first and second div?
Create your own insertAfter function
you can use JQuery it very simple
$(".class1").after( document.createTextNode("Hello") );

Categories

Resources