Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery find antecedent?

Tags:

jquery

When I want to find a child of an object I can use children(); when I want to find an object inside another object, not necessarily it's child, I can use find(). If I want to find a parent, I use parent(), but if I want to find an antecedent, not knowing if it's parent grandparent, grand-grandparent, how can I do it?

I'll give you an example: I am building a plugin that is to be applied to some 'input:text'.

In the end, I need to do something to the form that holds them. But sometimes, the text-boxes will be directly inside the form, or they can be inside an unordered list or inside a table.

Am I able to refer to the form in a general way?

like image 376
André Alçada Padez Avatar asked Feb 06 '11 15:02

André Alçada Padez


2 Answers

You can use jQuery's closest() method:

$('input:text').change(
function(){
    var ancestorFormElement = $(this).closest('form');
    // do stuff.
});

$('input:text').change(function() {
  var ancestorFormElement = $(this).closest('form');

  ancestorFormElement.addClass('hasInputChanged');
});
form {
  border: 2px solid #000;
  padding: 1em;
}
form.hasInputChanged {
  border-color: limegreen;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="#" method="post">
  <fieldset>
    <legend>Simple demo</legend>
    <label for="name">Text Input:</label>
    <input type="text" name="name" id="name" value="" tabindex="1" />
  </fieldset>
</form>

External JS Fiddle demo, for experimentation or development.

Or, instead, you could simply use the DOM approach which associates the <form> element with its descendant form-elements (<input />, <textarea>, <select> etc):

$('input:text').change(function() {
  var ancestorFormElement = this.form;

  // because 'this.form' returns a DOM node, it
  // must be converted to a jQuery object in 
  // order to utilise jQuery methods:
  $(ancestorFormElement).addClass('hasInputChanged');
});

$('input:text').change(function() {
  var ancestorFormElement = this.form;

  $(ancestorFormElement).addClass('hasInputChanged');
});
form {
  border: 2px solid #000;
  padding: 1em;
}
form.hasInputChanged {
  border-color: limegreen;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="#" method="post">
  <fieldset>
    <legend>Simple demo</legend>
    <label for="name">Text Input:</label>
    <input type="text" name="name" id="name" value="" tabindex="1" />
  </fieldset>
</form>

External JS Fiddle demo, for experimentation or development.

Further, because I'd strongly suspect that you want the changes – whatever they may be – to revert should the 'change' be undone, I'd suggest the following approach:

$('input:text').change(function() {
  var ancestorFormElement = this.form;

  // here we use the 'toggleClass(<class-name>, <switch>)'
  // method; where the 'switch' returns a Boolean true/false
  // if it evaluates to true then the class-name is added
  // and if it evaluates to false then the class-name is
  // removed:
  $(ancestorFormElement).toggleClass('hasInputChanged', this.value !== this.defaultValue);
});

$('input:text').change(function() {
  var ancestorFormElement = this.form;

  $(ancestorFormElement).toggleClass('hasInputChanged', this.value !== this.defaultValue);
});
form {
  border: 2px solid #000;
  padding: 1em;
}
form.hasInputChanged {
  border-color: limegreen;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="#" method="post">
  <fieldset>
    <legend>Simple demo</legend>
    <label for="name">Text Input:</label>
    <input type="text" name="name" id="name" value="" tabindex="1" />
  </fieldset>
</form>

External JS Fiddle demo, for experimentation or development.

Also, it's entirely possible to delegate the change event-handler to the <form> element itself, using the on():

$('form').on('change', function(e) {

  // here 'e' is the event-object passed to the
  // event-handling function; 'e.target' is the
  // element that received the initiating event:
  var changedEl = e.target;

  $(this).toggleClass('hasInputChanged', changedEl.value !== changedEl.defaultValue);
});

$('form').on('change', function(e) {
  var changedEl = e.target;

  $(this).toggleClass('hasInputChanged', changedEl.value !== changedEl.defaultValue);
});
form {
  border: 2px solid #000;
  padding: 1em;
}
form.hasInputChanged {
  border-color: limegreen;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="#" method="post">
  <fieldset>
    <legend>Simple demo</legend>
    <label for="name">Text Input:</label>
    <input type="text" name="name" id="name" value="" tabindex="1" />
  </fieldset>
</form>

External JS Fiddle demo, for experimentation or development.

It's also possible to pass a selector into the on() method to specify the elements that should initiate the given event (here the 'change' event) to trigger the event-handling bound to the ancestor:

// here we pass the selector, 'input[type=text]' to the
// method, which restricts the event-handling to only
// those events originating with <input> elements whose
// 'type' attribute is equal to 'text':
$('form').on('change', 'input[type=text]', function(e) {

  $(this).toggleClass('hasInputChanged', changedEl.value !== changedEl.defaultValue);
});

$('form').on('change', 'input[type=text]', function(e) {
  var ancestorFormElement = this.form;

  $(ancestorFormElement).toggleClass('hasInputChanged', this.value !== this.defaultValue);
});
form {
  border: 2px solid #000;
  padding: 1em;
}
form.hasInputChanged {
  border-color: limegreen;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="#" method="post">
  <fieldset>
    <legend>Simple demo</legend>
    <label for="name">Text Input:</label>
    <input type="text" name="name" id="name" value="" tabindex="1" />
  </fieldset>
</form>

External JS Fiddle demo, for experimentation or development.

And, finally, a plain JavaScript means of accomplishing the same behaviour:

// defining a named function to handle the
// event-handling, the 'event' argument is
// passed automagically from the
// addEventListener() method (below):
function changeHandler(event) {

  // 'this' is the element to which
  // event-handler was bound (again
  // automagically passed from
  // addEventListener()):
  var form = this,
    changed = event.target;

  // here we use the Element.classList API; which
  // works much as toggleClass() does, adding the
  // supplied class-name if the switch that follows
  // evaluates to true, removes it if the switch
  // evaluates to false:
  form.classList.toggle('hasInputChanged', changed.value !== changed.defaultValue);

}

// retrieving the <form> element using
// document.querySelector(), which returns
// the first element in the document that
// matches the CSS selector passed to the
// function:
var formElement = document.querySelector('form');

// using addEventListener to bind the named 
// function (changeHandler) as the event-
// handler for the 'change' event:
formElement.addEventListener('change', changeHandler);

function changeHandler(event) {
  var form = this,
    changed = event.target;

  form.classList.toggle('hasInputChanged', changed.value !== changed.defaultValue);

}

var formElement = document.querySelector('form');

formElement.addEventListener('change', changeHandler);
form {
  border: 2px solid #000;
  padding: 1em;
}
form.hasInputChanged {
  border-color: limegreen;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="#" method="post">
  <fieldset>
    <legend>Simple demo</legend>
    <label for="name">Text Input:</label>
    <input type="text" name="name" id="name" value="" tabindex="1" />
  </fieldset>
</form>

External JS Fiddle demo, for experimentation or development.

References:

  • CSS:
    • Attribute selectors.
  • JavaScript:
    • document.querySelector().
    • Element.classList.
    • EventTarget.addEventListener().
    • HTMLInputElement.
  • jQuery:
    • addClass().
    • change().
    • closest().
    • on().
    • toggleClass().
like image 57
David Thomas Avatar answered Oct 26 '22 21:10

David Thomas


I'm not entirely sure what your question is, as it isn't very clear as it is.

I think you may be looking for the jQuery parents() function though.

Example:

<table>
    <tr>
        <td id="content"></td>
    </tr>
</table>

$("#content").parents("table") should get the <table> element.

like image 40
Hello71 Avatar answered Oct 26 '22 21:10

Hello71