How to get parent using $(this) - javascript

I'm trying to further my understanding of traversing and correctly using $(this).
I understand $(this) is used in reference to the context. However, say I have three items that are identical to each other (HTML-wise) and if a user clicks on an input, I want the events to not only happen for the item the user selected, but be able to access the parent element ".item" as well. This way, I can hide other elements within ".item" because, again, the context would be the "input" that the user clicked.
This is where I am confused. When a user clicks on the input ($('input').on('click', doSomething);), I am limited to the context of the input - nothing is inside the input, so I want to access other elements that are out of the input context.
I then try and use $(this) to say I only want THIS event to happen for THIS item only, not affecting ALL items.
Here is a code example: JSFIDDLE
I've tried researching this and I can't find much information on an instance like this so hopefully this could benefit others too. Feel free to make edits to the content / heading as I've tried to be as specific as possible.

To get the immediate parent(s) of the element(s) in a jQuery set: parent. (If your set has only one element, as $(this) will, that will give you that element's immediate parent.)
To find the closest element(s) to the elements(s) in a jQuery set matching a given selector, starting with the current element(s): closest. (If your set has only one element, as $(this) will, that will give you the first element matching a selector starting with that one element, then looking at its parent, then its parent, etc.)

This should be your click-handler code :
function doSomething(event) {
$(event.target).parent().find('ul').hide();
}

Related

How do I use JQuery to iterate a form from the bottom to the top, most nested element first without knowing the id of the deepest element beforehand?

I have a dynamic form builder that create a form in an MVC web application.
It's arranged into sections and questions, sections contain questions or other sections.
The plan was to have some sections open based on the input of certain questions (so for instance checking a box saying you own a car makes the section on car details enabled). All sections which could be opened need to start disabled/hidden (so they can be opened on the relevant input).
All sections and questions have an id although unfortunately I won't know what these are until the page is loaded as Id's are generated dynamically, so i can't just start iterating up from a known deepest element, I have to find it first and then iterate..
I have no idea how to iterate through from the bottom up up, deepest first.
If I iterate from top to bottom, any nested openable sections within openable won't get disabled as the parent will be deactivated before it can be.
Help would be VERY MUCH appreciated.
Thank you.
Did you take a look at JQuery's closest() function?
Example:
function openParent(jq_element) {
jq_element.show();
if(jq_element.parent().length) {
openParent(jq_element.closest());
}
}
$('input').each(function() {
openParent($(this));
});
You could also try something with the parents() function, you can find the differences on the JQuery documentation pages:
.closest()
Begins with the current element
Travels up the DOM tree until it finds a match for the supplied
selector
The returned jQuery object contains zero or one element for each
element in the original set, in document order
.parents()
Begins with the parent element
Travels up the DOM tree to the
document's root element, adding each ancestor element to a temporary
collection; it then filters that collection based on a selector if
one is supplied
The returned jQuery object contains zero or more
elements for each element in the original set, in reverse document
order
UPDATE
To find the most deepest element, you could iterate over all elements that don't have a child element (so all 'deepest' elements):
$('body *:not(:has("*"))');
If you need to open sections based on checkboxes that are checked or not (like your own a car example) You could do something like this:
$('input:checkbox:checked').each(function () {
$( '#' + $(this).data('referenced-section-id-from-current-element') ).show();
});

Find related element using jQuery

Based on this DOM tree below when a comment reply button is clicked I need to use $(this) and then navigate to the next comment textarea .task-modal-cmt-reply-textarea
I am using jQuery and tried to use .parent().parent().closest('.task-modal-cmt-reply-textarea') and a few other combination without luck so far.
Can someone show me an efficient way to get this element into a var?
What I am trying to accomplish...
I have a click even on a comment reply button which insert a reply form into the DOM below a parent comment when the reply button is clicked using...
$document.on('click', '.cmt-reply-btn', function(e) {}
In this click event the reply form is put into the DOM with...
$parentCmtDomNode.after(cmtReplyFormTemplateHtml);
After the form is in the DOM I try to attach a jQuery plugin to it for #mention style capability using...
$('.task-modal-cmt-reply-textarea').mentionsInput({});
The problem
The #mention library works for the 1st clicked on comment form but all other reply forms do not work
another way to get a reference to that element, would be to do this:
var el = $(this).parent().parent().next().find('.task-modal-cmt-reply-textarea').eq(0);
note that the eq(0) just gives a single object back instead of an array with one element, which may or may not be necessary depending on what you want to do with it.
You need to do another .parent(), the two parent() you did only bring you up to the level of class "Activity-item Activity-comment" with data-activity-id = 12. Do another parent and you should be fine.
try this
var textarea_value=$(this).closest('.Activity-item').next('.Activity-item').find('form .task-model-cmt-reply-textarea').val();
or if its related with data-activityid = "12" so you can use
$(document).on('click','.cmt-reply-btn',function(){
var textarea_value = $(form[data-comment-parent-id = "'+$(this).attr('data-activityid')+' .task-modal-cmt-reply-textarea"]).val();
});
A more efficient way would be to use the parents api from jQuery then followed by your .closests
.parents('div')
The .parents() and .parent() methods are similar, except that the latter only travels a single level up the DOM tree. Also, $( "html" ).parent() method returns a set containing document whereas $( "html" ).parents() returns an empty set.
Then add the following sub selector to your closest chain.
.closest('textarea[name=^"task-modal-cmt-textarea"]')
This looks for the closest textarea with the name starting with task-modal-cmt-textarea. This is more efficient than what you have as this will eliminate any lookups on non textarea elements then it will only filter out the textareas that have that particular name.
EDIT: Updated Answer to the OP's recent edit.
$('.task-modal-cmt-reply-textarea').mentionsInput({});
This will select all of the ".task-modal-cmt-reply-textarea" that are on the screen at the time, it will not account for future ones. To achieve what you are looking for you should put a sub selector on this chain to allow it to attach to the newest form that was created.
$('.task-modal-cmt-reply-textarea',$($parentCmtDomNode).next('textarea')).mentionsInput({});
This should be placed after the
$parentCmtDomNode.after(cmtReplyFormTemplateHtml);
Try this:
var txt_html = $(this).parents('.Activity').children("textarea:first").html();
var txt_val = $(this).parents('.Activity').children("textarea:first").val();
In the parents() function you need to use the closest parent class/ id.
var el = $(this).parents('.Activity-item').next().find('.task-modal-cmt-reply-textarea').eq(0);

Adding an event listener to a div to perform an event if the div becomes empty (has no children)

My goal is the following: create a listener that will be bound to a div and it will fire up if there are no children left in that div.
I keep seeing how to bind a listener to say onClick etc.. but I cannot seem to find anyone that deals with actual states of the elements (empty, at least one child, etc... ). I have not started coding anything yet because I am not sure what kind of approach I need to take, since I am pretty new to JavaScript development. I am not necessarily looking for an answer with code in it but more of an advise on what approach to take.
One of the approaches that I was thinking of was to simply have a function call every single time I make a change to the div such as deleting a child but that seems too trivial. I want to create some kind of automation in that process of checking for no children.
jQuery has remove event fired when element is removed
$(el).on("remove", function () {
alert("Element was removed");
});
You could use live (if they are appended dynamically to parent container) or on (if statically) method to bind this event to child nodes of particular container and on every remove event check if parent container has any child nodes. If not then do some actions.
You cannot assign a listener to a div element to check if the element has no children(done automatically without knowing which function is removing the children, but only knows that there was a child removed). Granted you could do a function to check every so many seconds but that is not what I wanted. Anyways, where I remove the children, I simply added a function that checks if the parent is left with no children and it handles it there.

jQuery on() method - which way to use is better for performance?

Is it better to attach the on() event to the document or a closer parent?
Note: Initially this question had another aspect and a different topic. It became obsolete really quickly (typo in the source code)
The best key for performance using jQuery is to use an id as the initial identifier. For example:
$('#my_id').on('click', 'tag.my_class', function () {
...
});
This allows jQuery to go straight to the container, and then begin trawling from there.
if you bind the "on" event to the closest parent will produce exactly what are you looking for, click function will works fine even if it is appended to document, but in future if you append any elements with class "clickable" will also get binded. so its always good practice to append the "on" event to closest parent rather than whole document.
if you want more specific you can use
$("ul.media-grid").on('click', 'li.clickable', function () {
alert("works")
});
as it will get the ul with the class "media-grid" and appends the event to the li's with class "clickable"

How to change attribute of surrounding div/parent effectively?

I have a table with some radiobuttons in it. When i click on a radiobutton, i want to update two of the sorrounding containers ID attribute (a div and a table). The problem is, i need to go 4 and 6 levels up, and the only way i know how to do this is parent().parent().parent().parent() etc.
I am looking for a better solution, and was hoping someone could point me in the right direction. You can see an image of how the "parent-child" tree is here:
http://imageshack.us/photo/my-images/834/imgkz.png/
I already have a clickhandler etc set up.
Basicly i need to check if the table's id attribute is "answeredTable", if not i need to change it. Also i need to check if the div two levels up from the table is "answered", if not, i need to change that too.
Thanks
You can use .closest('#answeredTable') or .parents('#answeredTable').
Using .parent() only selects the first parent element upon the DOM tree, selecting .closest() will allow you to walk up to DOM tree and match until it finds the element, while .parents() will return the whole parentset of the DOM and match the element in the whole parentset.
You need to use .parents() that go through multiple level of the DOM
For instance, in your example, you could get the surrounding div with this code:
$("#Q_18_2015").parents("div#answered")
By the way, id should be unique, or else, your code might probably not work. You should use classes instead.
<div class="answered">
Thus, the code would become:
$("#Q_18_2015").parents("div.answered")
provided that Q_18_2015 is really a unique id
I think what you want to use is closest http://api.jquery.com/closest/
you can use .parents
$("element").parent(".parentClass")
parents will go up the DOM until finds the parent with class parentClass

Categories

Resources