How do I go about getting a reference to an element nested inside another element I can find by getElementByID()?
I have this so far:
<table>
<tr id="templateRow" style="display: none;">
<td><input name="f_name[]" type="text"></td>
<td><textarea name="f_description[]" rows="4"></textarea></td>
<td><input name="f_category[]" type="text"></td>
</tr>
</table>
and have some JS that adds in copies of that to build out the table (removing the id and style attributes as I go).
Assuming I have a reference to the <tr>, how do I reference the input named f_name[] within that table row?
Background: For the moment I have temporary id's on the nested elements, removing them too as I go. The tricky situation I have is that I have a function that adds 1 row (and returns a reference to it), and another function that adds multiple rows (calling the addOneRow function) .. and I want the addManyRows function to end up setting the focus on the first row added.
In any reasonably recent browser, you can use the querySelector method to query for children of the element.
Example:
var templateRow = document.getElementById('templateRow');
var f_name = templateRow.querySelector('[name="f_name[]"]');
var f_description = templateRow.querySelector('[name="f_description[]"]');
var f_category = templateRow.querySelector('[name="f_category[]"]');
console.log(f_name.outerHTML);
console.log(f_description.outerHTML);
console.log(f_category.outerHTML);
<table>
<tr id="templateRow" style="display: none;">
<td><input name="f_name[]" type="text"></td>
<td><textarea name="f_description[]" rows="4"></textarea></td>
<td><input name="f_category[]" type="text"></td>
</tr>
</table>
Use Element#querySelector method and where use attribute equals selector to get based on the attribute.
tr.querySelector('td input[name="f_name[]"]')
var tr = document.getElementById('templateRow');
tr.querySelector('td input[name="f_name[]"]').style.color = 'red';
<table>
<tr id="templateRow" style="">
<td>
<input name="f_name[]" type="text">
</td>
<td>
<textarea name="f_description[]" rows="4"></textarea>
</td>
<td>
<input name="f_category[]" type="text">
</td>
</tr>
</table>
Related
I have a Javascript / Jquery function that controls groups of checkboxes.
The checkboxes are created on PHP form from a database call so I am iteratively going through a recordset and creating checkboxes in html.
For each checkbox I assign it a class of "checkboxgroup" + a numeric identifier to create a group of 'like' records.
I end up with multiple checkboxes like this:
<tr class="tablebody">
<td><input name="contactresolveid2048" id="contactresolveid2048" type="checkbox" class="checkboxgroup0"/></td>
<td>David Smith</td>
</tr>
<tr class="tablebody">
<td><input name="contactresolveid19145" id="contactresolveid19145" type="checkbox" class="checkboxgroup0"/></td>
<td>graham Foots</td>
</tr>
<tr class="tablebody">
<td><input name="contactresolveid19146" id="contactresolveid19146" type="checkbox" class="checkboxgroup0"/></td>
<td>Tom Silly</td>
</tr>
As you can see, these 3 checkboxes have a class of 'checkboxgroup0'
The following function detects a click on ANY of the checkbox groups on a form (of which there may be many) and unchecks any checkboxes (belonging to the same group) that are not the clicked one.
$('[class^="checkboxgroup"]').click(function() {
var thisClass = $(this).attr('class');
var $checkboxgroup = $('input.'+thisClass);
$checkboxgroup.filter(':checked').not(this).prop('checked', false);
});
Under most circumstances this works fine when the only class is 'checkboxgroup0'.
However when validation takes place JQuery validate appends a 'valid' or 'error' class to the class list of any fields that pass or fail validation, so I can endup having an .attr(class) of 'checkboxgroup0 valid'.
My question is this:
How do I return the whole class name of the partially selected class WITHOUT any extraneous classes?
By using the selector $('[class^="checkboxgroup"]') I need the whole part of that selector 'checkboxgroup0' and no other classes that may be assigned to it.
This issue you've encountered is one of the reasons why using incremental id/class attributes are not good practice.
To work around this issue with your JS you can instead use the same class on every checkbox. You can then group them by a data attribute instead. Using this method means that the number of classes on an element or their position within the class attribute string does not matter.
Try this example:
$('.checkboxgroup').click(function() {
let $this = $(this);
let $group = $(`.checkboxgroup[data-group="${$this.data('group')}"]`);
$group.not(this).prop('checked', false);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr class="tablebody">
<td><input name="contactresolveid2048" id="contactresolveid2048" type="checkbox" class="checkboxgroup" data-group="0" /></td>
<td><label for="contactresolveid2048">David Smith</label></td>
</tr>
<tr class="tablebody">
<td><input name="contactresolveid19145" id="contactresolveid19145" type="checkbox" class="checkboxgroup" data-group="0" /></td>
<td><label for="contactresolveid19145">graham Foots</label></td>
</tr>
<tr class="tablebody">
<td><input name="contactresolveid19146" id="contactresolveid19146" type="checkbox" class="checkboxgroup" data-group="0" /></td>
<td><label for="contactresolveid19146">Tom Silly</label></td>
</tr>
</table>
However, it's worth noting that what you're attempting to do can be far better achieved using HTML alone. Simply use a radio input and give them all the same name attribute, then you get the behaviour you're trying to create for free:
<table>
<tr class="tablebody">
<td><input name="contactresolve" id="contactresolveid2048" type="radio" /></td>
<td><label for="contactresolveid2048">David Smith</label></td>
</tr>
<tr class="tablebody">
<td><input name="contactresolve" id="contactresolveid19145" type="radio" /></td>
<td><label for="contactresolveid19145">graham Foots</label></td>
</tr>
<tr class="tablebody">
<td><input name="contactresolve" id="contactresolveid19146" type="radio" /></td>
<td><label for="contactresolveid19146">Tom Silly</label></td>
</tr>
</table>
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 a table that consists of many text input fields which the user can assign values to. My goal is that if the user "onBlur"s any of the fields then a function will activate. I could resolve the issue by marking each cell individually, however it would be very repetitive and i'm sure there's a more efficient way around this.
To demonstrate:
<table>
<tr>
<td>I</td>
<td><input type="text" id="whatever1"></td>
</tr>
<tr>
<td>Love</td>
<td><input type="text" id="whatever2"></td>
</tr>
<tr>
<td>Stack Overflow</td>
<td><input type="text" id="whatever3"></td>
</tr>
</table>
With JS:
var e1 = document.getElementById('whatever1');
e1.onblur = alias;
function alias() {
alert('started');
}
and then repeat this for each input box another 2 times. Or hopefully there's an easier way.
You can delegate the event and put a listener on a containing element:
var e1 = document.getElementById('containing-table');
e1.addEventListener('blur', function(e){
alert(e.target);
}, true);
and the modified html:
<table id="containing-table">
<tr>
<td>I</td>
<td><input type="text" id="whatever1"></td>
</tr>
<tr>
<td>Love</td>
<td><input type="text" id="whatever2"></td>
</tr>
<tr>
<td>Stack Overflow</td>
<td><input type="text" id="whatever3"></td>
</tr>
</table>
here's a fiddle: http://jsfiddle.net/oj2wj1d6/7/
The advantage of this is that you can actually remove and add input elements and the listener will capture events on new nodes. You can add conditional statements inside of the function in addEventListener in order to further filter how you would want to respond to different types of event targets.
with jQuery, you could do something as simple as:
$("table").on("blur", "input", function(e){
alert(e.target);
});
Some useful documentation to learn more:
The blur event, scroll down for details about event delegation.
addEventListener.
more about doing event delegation in vanilla JS
<table>
<tr>
<td>I</td>
<td><input class="blurMe" type="text" id="whatever1"></td>
</tr>
<tr>
<td>Love</td>
<td><input class="blurMe" type="text" id="whatever2"></td>
</tr>
<tr>
<td>Stack Overflow</td>
<td><input class="blurMe" type="text" id="whatever3"></td>
</tr>
</table>
Then in javascript
//inputs as NodeList
var inputs = document.querySelectorAll(".blurMe");
//Convertion to Array
var inputsArr = Array.prototype.slice.call(input);
// Loop to asign event
inputsArr.forEach(function(item){
item.onBlur = alias;
});
Add a common class to all your element and use this for select all element getElementByClassname. if you want see exact what if your curent element add parameter event your function. and e.target give you DOM element.
how about this ?
<script>
document.getElementById()
var arr = document.getElementsByClassName('whatever');
for(var i=0;i<arr.length;i++)
{
arr[i].onblur=alias;
}
function alias() {
alert('started');
}
</script>
<table>
<tr>
<td>I</td>
<td><input type="text" class="whatever"></td>
</tr>
<tr>
<td>Love</td>
<td><input type="text" class="whatever"></td>
</tr>
<tr>
<td>Stack Overflow</td>
<td><input type="text" class="whatever"></td>
</tr>
</table>
I have a table, and each row has a button to add a new row on top of it. Each row has new inputs.
I know how to add a row on top of the table, but not on top of each row that I'm clicking on the button. Would anyone have a tip on how to solve it? I might be able to do it, but the solution I see is very complicated, and I'm sure there must be a smarter solution.
Oh, also I don't know how to update the parameter sent in the insertNewRow(id) function.
So far this is what I have:
<script type="text/javascript">
function insertNewRow(id){
var row = document.getElementById("bottomRow");
var newrow = row.cloneNode(true);
console.log(newrow);
var newInputs = newrow.getElementsByTagName('input');
var allRows = row.parentNode.getElementsByTagName('tr');
row.parentNode.insertBefore(newrow, row);
var i=row.rowIndex;
console.log(i);
}
</script>
<table id="myTable">
<tr>
<td>Title1:</td>
<td></td>
<td>Title2:</td>
<td></td>
<td>Title3:</td>
<td></td>
<td></td>
</tr>
<tr>
<td><input class="c1" readonly maxlength="9" size="7" id="gTop" type="text" value ="11"></td>
<td> <-></td>
<td id="l1"><input class="c2" style="width:35px;" maxlength="9" size="7" type="text" id="lTop" value="33"></td>
<td>=</td>
<td id="rv1"><input id="rvTop" input class="c2" style="width:105px;" maxlength="100" size="37" type="text" value="blahblahblah"></td>
<td></td>
<td>x</td>
</tr>
<tr id="bottomRow">
<td><input class="c1" readonly maxlength="9" size="7" id="gBottom" type="text" value =""></td>
<td> </td>
<td id="l1"><input class="c2" style="width:35px;" maxlength="9" size="7" type="text" id="lBottom" value="11"></td>
<td>=</td>
<td id="rv1"><input id="rvBottom" input class="c2" style="width:105px;" maxlength="100" size="37" type="text" value="blahblahblah"></td>
<td><button type="button" onclick="insertNewRow(1)">+</button></td>
<td>x</td>
</tr>
</table>
In the onclick attribute, instead of just calling insertNewRow(), do something like
insertNewRow.apply(this);
The this keyword inside the onclick attribute is a reference of the clicked element. With insertNewRow.apply(this), we'll be calling insertNewRow() and at the same time, assign the this keyword inside that function call to the clicked element or in this case, the button (if we don't do that, this inside insertNewRow() will be a reference to the Window object instead). Then in, your insertNewRow() function, check if the current element being clicked on is a tr element. If not, go up by one level and see if that element is a tr element. Keep doing that until you get to the first tr element. So, basically you'll be searching for the closest tr element.
<button type="button" onclick="insertNewRow.apply(this);">+</button>
function insertNewRow(){
var row = null,
el = this;
// Get the closest tr element
while (row === null)
{
if (el.tagName.toLowerCase() === 'tr')
{
row = el; // row is now the closest tr element
break;
}
el = el.parentNode;
}
// Rest of the code here
}
JsFiddle
If you're still not sure what Function.apply() is, take a look at the documentation here.
I have an html code like this -
<table border="0" cellspacing="2" cellpadding="2" width="99%" id="subAccTable">
<tr>
<h2>Sub Accounts</h2>
</tr>
<tr>
<th>action </th>
<th>account</th>
<th>homeDir</th>
<th>primaryGroup</th>
</tr>
<tr>
<td><input type="hidden" name="vtierId" value="" /></td>
<td><input type="text" name="subAcc"
value=""/></td>
<td><input type="text" name="subHomeDir"
value=""/></td>
<td><input type="text" name="subPriGroup"
value=""/></td>
</tr>
</table>
Now i want to fill the values of textboxes named subAcc, subHomeDir, subPriGroup using javascript. How can i do it ?
There are multiple ways to get the proper DOMElement; including:
Giving each element an id and getting it using document.getElementById
Using document.getElementsByName. This is not preferred since there can be multiple elements with the same name, however there can be only one with the same id.
Using the form directly. For example if your form's name is form1: form1.subAcc
Using document.getElementsByTagName('input') and then getting the proper index.
I'd recommend using the id to retrieve the proper element.
The easiest way would be to give these textboxes a unique id, then reference them like this:
<input type="text" id="subHomeDir" name="subHomeDir" value=""/>
var tb = document.getElementById("subHomeDir");
tb.value = "foo";
If you're stuck with the names only, then you can use document.getElementsByName, just remember, this will return a collection of elements (since names are not necessarily unique), which you'll have to index:
var tb = document.getElementsByName("subHomeDir")[0];
tb.value = "foo";