I'm using jQuery 1.12.4 to set get the value of the closest preceding element using class selector. I'm unable to select the closest element.
$(function() {
$("[class='quickSelect']").blur(function() {
var obj = $(this);
alert($(this).parent());
// alert($(this).closest("[class~='endDateField']"));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td align="right">
Start Date
</td>
<td>
<input type="text" name="debitStartDate" value="" class="dateField startDateField">
</td>
<td align="right">
End Date
</td>
<td>
<input type="text" name="debitEndDate" value="" class="dateField endDateField">
</td>
<td class="debitApportioner" style="align:right">
Quick Select
</td>
<td class="debitApportioner" colspan="2">
<select class="quickSelect">
<option> SELECT </option>
<option> JANUARY </option>
<option> FEBRUARY </option>
<option> MARCH </option>
</select>
<input class="quickSelect" type="text" />
</td>
</tr>
</table>
Try this:
$(".quickSelect").blur(function() {
var obj = $(this);
obj.closest('tr').find('.endDateField'); // will find the endDateField in the current row
});
closest() only traverses up the trees ancestors and stops at the first element that matches the selector so the above says find the closest ancestor tr to the input then find any endDateField inside that tr
Related
I need a way to retrieve elements of a given element which are not children of certain other elements. To distinguish between these "parent" elements I've been using a data attribute.
This is an example of my following HTML stucture:
<form method="post" data-component-id="3">
<table border="0">
<thead>
<tr>
<th></th>
<th>First Name</th>
<th>Last Name</th>
<th>Date of Birth (dd/mm/yyyy)</th>
<th>Sex</th>
</tr>
</thead>
<tbody>
<tr data-component-id="8">
<td>Spouse</td>
<td><input name="txtFirstName_1" type="text" maxlength="255" id="txtFirstName_1" data-mapping-id="Person.Firstname"></td>
<td><input name="txtLastName_1" type="text" maxlength="255" id="txtLastName_1" data-mapping-id="Person.Lastname"></td>
<td><input name="txtDOB_1" type="text" maxlength="10" id="txtDOB_1" data-mapping-id="Person.Birthday"></td>
<td>
<select name="ddlSex_1" id="ddlSex_1" data-mapping-id="Person.Sex">
<option value=""></option>
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</td>
</tr>
<tr data-component-id="9">
<td>Child</td>
<td><input name="txtFirstName_2" type="text" maxlength="255" id="txtFirstName_2" data-mapping-id="Person.Firstname"></td>
<td><input name="txtLastName_2" type="text" maxlength="255" id="txtLastName_2" data-mapping-id="Person.Lastname"></td>
<td><input name="txtDOB_2" type="text" maxlength="10" id="txtDOB_2" data-mapping-id="Person.Birthday"></td>
<td>
<select name="ddlSex_2" id="ddlSex_2" data-mapping-id="Person.Sex">
<option value=""></option>
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</td>
</tr>
<tr data-component-id="9">
<td>Child</td>
<td><input name="txtFirstName_3" type="text" maxlength="255" id="txtFirstName_3" data-mapping-id="Person.Firstname"></td>
<td><input name="txtLastName_3" type="text" maxlength="255" id="txtLastName_3" data-mapping-id="Person.Lastname"></td>
<td><input name="txtDOB_3" type="text" maxlength="10" id="txtDOB_3" data-mapping-id="Person.Birthday"></td>
<td>
<select name="ddlSex_3" id="ddlSex_3" data-mapping-id="Person.Sex">
<option value=""></option>
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</td>
</tr>
</tbody>
</table>
<input type="button" name="submit" value="SUBMIT">
Note: The reason there are two data-component-id="9" attributes is because I treat this attribute as a type for mapping purposes in my back-end. (8 = Spouse data, 9 = Child data)
I created a JavaScript function which accepts one element and recursively builds a Component object, holding an ID, an array of its fields, and sub-components (recursive).
// Component Object
function Component(componentID, fields, subComponents) {
this.ComponentID = componentID; // Numeric
this.Fields = fields; // Array
this.Components = subComponents; // Array
}
// Recursively build component (and sub-components)
$.fn.formDataToComponent = function() {
var componentID = $(this).attr("data-component-id");
var componentName = "";
var fields=[];
var subComponents=[];
var subComponentsIndex=0;
// Recursively create the sub components
$(this).find("[data-component-id]").each(function(oSubComponent){
subComponents[subComponentsIndex] = $(oSubComponent).formDataToComponent();
subComponentsIndex++;
});
$(this).find('[data-mapping-id]').each(function() {
// $(this).find('[data-mapping-id]') will retrieve all elements with the data attribute (therefore 12 elements will be selected)
// With the list of these elements, I want to select ONLY those which are closest to the parent element with the attribute "data-component-id".
// Therefore in this particular scenario I only want to select the 4 elements of each "tr" element with each recursive call.
// I need to do so in a way that is dynamic and is based on the data attribute as I'll be using this with various forms.
});
return new Component(componentID, componentName, fields, subComponents);
}
I've looked at using the .not() function in jQuery but I don't think this works how I think it does. I'll continue searching for the solution, but if anyone knows of an easy/efficient way to do so please, I would really appreciate the help!
Solution
For a solution to your problem, check jQuery's .filter function here: http://api.jquery.com/filter/
// Get list of sub components
var subComponentArray = $(this).find("[data-component-id]");
// Get all fields that are not within the sub components
$(this).find('[data-mapping-id]').filter(function(){
return $(this).closest(subComponentArray).length === 0;}).each(function(index) {
// DO STUFF
});
For a solution to your problem, check jQuery's .filter function here:
http://api.jquery.com/filter/
and do something like this:
$(this).find('[data-mapping-id]').filter(function(){
return $(this).closest("[parent selector you don't want]").length === 0;
}).each(function() { .... });
Might be able to use not(). Using your Root, Child and Field tags as example if you only wanted the nested Field inside Child you can do:
$('Field').not("Root > Field');
This would exclude any Field that was a direct child of Root
It isn't clear what you are trying to filter exactly
I have a dataTable that each row continue same class and same event.
I have this
<td>
<select name="produits" onchange="loadFourAjax(this)" class="produits">
<option value="0" selected="selected">
<c:forEach var="i" items="${produits}">
<option value="<c:out value="${i.id}" />">
<c:out value="${i.designation}" />
</option>
</c:forEach>
</select>
</td>
<td><select name="fournisseurs" class="fournisseurs"
onchange="loadRefFourAjax(this)">
</select>
</td>
<td class="ref">
</td>
<td class="prix">
</td>
<td>
<input name="qte" class="qte" onkeyup="calculTotalHt(this)" type="text"/>
</td>
<td id="total"></td>
My question how i can know that the query come from a current row of table, because i one to use it to select class prix and qte to calculate prix total of each row.
You are already getting the reference to the current element using this
That is
loadFourAjax(this) or loadRefFourAjax(this)
You can access its parent row node (tr) using
function loadFourAjax(thisObj)
{
//other code
var parentTr = thisObj.parentNode.parentNode;
var prix = parentTr.querySelector(".prix").innerHTML;
}
use querySelector to get the prix value
Please move for loop from <td> level to <tr> level and append id (${i.id} from your code) to fournisseurs name.
So I have a table like this:
<table id="TblProduits" class="TblProduitsLayout">
<thead>
<tbody>
<tr class="placeholderRow">
<td>
<input class="PrixUnitr" type="number" />
</td>
<tr class="placeholderRow">
<tr class="placeholderRow SousTotal">
<td>
<input class="MontnHT" type="text" disabled="disabled" min="0"/>
</td>
<tr class="placeholderRow">
<tr class="placeholderRow SousTotal">
<td>
<input class="MontnHT" type="text" disabled="disabled" min="0">
</td>
</tbody>
</table>
I want to change the value of the fisrt occurence of the input with classname MontnHT contained inside a tr with classname SousTotal when the value of the input with classname PrixUnitr is changed, so I created an event like this:
$('body').on('change', '.PrixUnitr', function() {
$(this).closest('tr').nextAll("tr.SousTotal").find("input.MontnHT").val("foo");
});
My problem is that is also changes the other inputs contained inside a TR with the same classname SousTotal , as I want to change just the first occurence , what am I doing wrong? and how can it be fixed?
use .first() or .eq(0) to get the first occurrence of the element
$(this).closest('tr').nextAll("tr.SousTotal").first().find("input.MontnHT:first").val("foo");
or
$(this).closest('tr').nextAll("tr.SousTotal:eq(0)").find("input.MontnHT:eq(0)").val("foo");
I have next code:
<tr>
<td>
<select class="select_big" name="additional_field" id="<?=$field['id'];?>" required>
<option value="0">Выберите значение</option>
...
</td>
</tr>
<tr>
<td>
<select class="select_big" name="additional_field" id="<?=$field['id'];?>" required>
<option value="0">Выберите значение</option>
...
</td>
</tr>
<tr>
<td>
<select class="select_big" name="additional_field" id="<?=$field['id'];?>" required>
<option value="0">Выберите значение</option>
...
</td>
</tr>
<tr>
<td>
<select class="select_big" name="additional_field" id="<?=$field['id'];?>" required>
<option value="0">Выберите значение</option>
...
</td>
</tr>
When I select the second "select" element, I need to disable all the next one.
If I select 1 need to disable 3 and 4, if I select 2 I need to disable only 4.
Count of element could be different.
How I can get all elements next the select?
I try next:
<script type="text/javascript">
$("[name=additional_field]").change(function(e) {
field_data = '#' this.id.replace(/[* .]/g, "\\$&");
$(field_data).parent().parent().nextAll().each(function(i) {
console.log($(this)('[name=additional_field]'));
});
});
</script>
But I receive next error:
Uncaught TypeError: object is not a function
Help me please.
I think you can do it simpler without confusing traversal of the parent nodes:
var $sel = $('.select_big').change(function() {
$sel.filter(':gt(' + $sel.index(this) + ')').prop('disabled', +$(this).val());
});
Demo: http://jsfiddle.net/VFcF9/
It will also reenable selectboxes if you select default option back.
The error you were getting is because of this line:
$(this)('[name=additional_field]')
The first part, $(this), returns a jQuery object, and that object is not a function so you can't follow it with more parentheses.
As for your requirement to disable all of the following select elements, perhaps:
$("[name=additional_field]").change(function(e) {
$(this).closest("tr").nextAll("tr").find("[name=additional_field]").prop("disabled", true);
});
This should do it
$("[name=additional_field]").change(function(e) {
var f = $(this).closest('tr') //find the closest parent tr
.nextAll('tr') //find all tr that follows
.find('select.select_big') //from them, get all select
//f should be all the selects the follow what changed
});
I want to remove the current <tr> and the yellow <tr> too when I click to the basket icon on the right.
Here is a screenshot :
Here is my html code of the two rows which I want to delete by the click:
<tr>
<td class="bar_td" colspan=7>
<strong>PRESTATION 2</strong>
</td>
</tr>
<tr class="ligne_suppr">
<td class="jr_td">
<img class="jour_prest" src="img/ico/jour_presta.png" alt="" width="16" height="16" /> Mardi 24 jan 2011
<p>ou</p>
<img class="jour_prest" src="img/ico/jour_presta.png" alt="" width="16" height="16" /> Mercredi 25 jan 2011
</td>
<td class="cr_td">
<select>
<option value="h9">10h30</option>
<option value="h10">11h30</option>
</select>
<select>
<option value="h11">10h30</option>
<option value="h12">11h30</option>
</select>
</td>
<td class="rp_td">
<select>
<option value="h13" SELECTED>2h00</option>
<option value="h14">3h00</option>
</select>
</td>
<td class="mn_td">
<select>
<option value="h15">2h00</option>
<option value="h16" SELECTED>6h00</option>
</select>
</td>
<td class="tt_td">
<strong>8h.</strong>
</td>
<td class="pttc_td">
<strong>148 €</strong>
</td>
<td class="cor_td">
<a href="#">
<img src="img/ico/corbeille.png" alt="" width="13" height="13" />
</a>
</td>
</tr>
and the Javascript code :
<script>
$(".ligne_suppr a").click(function(e) {
e.preventDefault();
($(this).parent()).parent().remove();
})
</script>
But with this code I can only remove the big <tr> and the yellow One stays.
Have you any idea?
This is basically going to tough to do when you dont have a specific way to select the two rows.
Create a global javascript function to remove the elements by taking the element's id
function deleteRows(row, yellow) {
row = document.getElementById(row);
row.parentNode.removeChild(row);
yellow = document.getElementById(yellow);
yellow.parentNode.removeChild(yellow);
}
Using jQuery you can do something like this
$(".ligne_suppr a").click(function(e) {
e.preventDefault();
var toprow = $(this).closest("tr");
toprow.prev().remove(); // remove the yellow
toprow.remove(); // remove the row
});
$('.ligne_suppr a').click(function(e) {
e.preventDefault();
var parent = $(this).parent().parent(); // parent <tr> of the anchor tag
var previous = parent.prev(); // <tr> before the parent <tr>
parent.remove();
previous.remove();
});