how to get nested selectors in siblings - javascript

I need to find the siblings of one element. The object I desire to get is nested input. The code belove navigates to td[2] where I need to do some comparison. Afterwords when the comparison is made I need to get to td[4] which contains input. I did try to use nextsibling function but something goes wrong :( Here is the image of html: HTML
var inputs = document.querySelectorAll("table.table.table-condensed.table-top-spacing tr td:nth-child(2)");
inputs.forEach((input)=>{
var final_input = input.find("input[name='quantity']");
final_input.click;
});

According to docs Using Node.nextSibling Node.firstChild or Node.previousSibling may refer to a whitespace text node rather than the actual element.
You can track the element's siblings with the example introduced in the MDN documentation here.
var el = input;
i = 1;
while (el) {
if(el.nodeName ==="TARGET_ELEMENT")
break;
console.log(i, '. ', el.nodeName);
el = el.previousSibling;
i++;
}

I think the root cause of your problem is that find is not a method that exists on HTML elements. You might be mistaking it for JQuery.
Instead, you want to use parentElement.querySelector:
const cells = document.querySelectorAll('table tr td:nth-child(2)');
cells.forEach(cell => {
if (cell.textContent === '1') {
const input = cell.parentElement.querySelector('input[name="quantity"]');
input.value = 'matched';
}
})
<table>
<tr>
<td>cell</td>
<td>1</td>
<td>input</td>
<td><input type="text" name="quantity" /></td>
</tr>
<tr>
<td>cell</td>
<td>0</td>
<td>input</td>
<td><input type="text" name="quantity" /></td>
</tr>
<tr>
<td>cell</td>
<td>1</td>
<td>input</td>
<td><input type="text" name="quantity" /></td>
</tr>
</table>

Related

Sort checkbox(checked and unchecked) in table

I want to sort my checkbox when i click on the X:
JS to sort my checkbox(checked and unchecked)?
I got no idea how to write it. please help.
The following code is borrowed.
The Price and stock value will be pass from other JS file using router.
But for now I make it simple because I want to know how to sort the checkbox.
var sortedPrice = false;
function sortPrice() {
$('#myTable').append(
$('#myTable').find('tr.item').sort(function (a, b) {
var td_a = $($(a).find('td.sortPrice')[0]);
var td_b = $($(b).find('td.sortPrice')[0]);
if(sortedPrice){
if(td_a.html() == 'Free') return -1;
return td_b.html().replace(/\D/g, '') - td_a.html().replace(/\D/g, '');
}else{
if(td_a.html() == 'Free') return 1;
return td_a.html().replace(/\D/g, '') - td_b.html().replace(/\D/g, '');
}
})
);
if(sortedPrice) sortedPrice = false;
else sortedPrice = true;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table" id="myTable">
<tr>
<th onclick="sortPrice()">Price</th>
<th>Stock</th>
<th>%</th>
<th>X</th>
</tr>
<tr class="item">
<td class="sortPrice">1</td>
<td>1</td>
<td>2</td>
<td><input type="checkbox" value="1"></td>
</tr>
<tr class="item">
<td class="sortPrice">4</td>
<td>3</td>
<td>1</td>
<td><input type="checkbox" value="2"></td>
</tr>
<tr class="item">
<td class="sortPrice">7</td>
<td>4</td>
<td>6</td>
<td><input type="checkbox" value="3"></td>
</tr>
<tr class="item">
<td class="sortPrice">2</td>
<td>7</td>
<td>8</td>
<td><input type="checkbox" value="4"></td>
</tr>
<tr class="item">
<td class="sortPrice">3</td>
<td>4</td>
<td>2</td>
<td><input type="checkbox" value="5"></td>
</tr>
</table>
I would try to make the click handler generic by taking the following steps:
Create a function that takes an array of pairs, and sorts that array by the first value in every pair, and returns the sorted array with just the second value from each pair in sorted order. This generic function can be used to pass pairs of cell-content and corresponding row element. This function could also take care of reversing the order when the input pairs were already sorted.
Create a single click handler for the td elements (the column headers). Let it collect the cells in the corresponding column, and for each cell determine whether the checkbox state should be taken as value, or the text content of that cell.
After sorting the values in the column with the first function, the rows can be fed into the table again.
Use the compare function from Intl.Collator so to have numeric sort when appropriate.
This way you can do away with some of the HTML (onclick, sortPrice, item, ...)
const {compare} = new Intl.Collator(undefined, {numeric: true});
function sortSecondByFirst(pairs) {
const sorted = [...pairs].sort(([a], [b]) => compare(a, b))
.map(([,a]) => a);
if (pairs.every(([,a], i) => a === sorted[i])) {
sorted.reverse(); // Was already sorted
}
return sorted;
}
$("th", "#myTable").click(function () {
sortColumn($(this).index());
});
function sortColumn(colIdx) {
const $cells = $(`tr > td:nth-child(${colIdx+1})`, "#myTable");
$("#myTable").append(
sortSecondByFirst($cells.get().map((cell) => {
const $input = $('input[type=checkbox]', cell);
const value = $input.length ? $input.prop("checked") : $(cell).text();
return [
value,
$(cell).parent()
];
}))
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="myTable">
<tr>
<th>Price</th><th>Stock</th><th>%</th><th>X</th>
</tr>
<tr>
<td>1</td><td>1</td><td>2</td>
<td><input type="checkbox" value="1"></td>
</tr>
<tr>
<td>4</td><td>3</td><td>1</td>
<td><input type="checkbox" value="2"></td>
</tr>
<tr>
<td>7</td><td>4</td><td>6</td>
<td><input type="checkbox" value="3"></td>
</tr>
<tr>
<td>20</td><td>7</td><td>8</td>
<td><input type="checkbox" value="4"></td>
</tr>
<tr>
<td>3</td><td>4</td><td>2</td>
<td><input type="checkbox" value="5"></td>
</tr>
</table>
Quite honestly if u have a choice I'd always go use Vue, react or the like as a ui framework. There this is simpler and u have a better -in my eyes - split of html template and data. Vue is quite easy to learn from my experience too.(great tutorials eg on YouTube)
That said in jQuery I guess I would write a sort function like the one u got there that via onclick event it triggered when X is clicked on and for the sorting write a similar compare function as above. Eg
(a,b) => a.checked - b.checked;
Hope this makes sense to you or where precisely do u struggle?

sum of column using jquery [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I need to sum of column With OnKeyup or OnChange
Here's my code:
$(document).ready(function() {
$(".expenses").on('keyup change', calculateSum);
});
function calculateSum() {
var $input = $(this);
var $row = $input.closest('tr');
var sum = 0;
$row.find(".expenses").each(function() {
sum += parseFloat(this.value) || 0;
});
$row.find(".expenses_sum").val(sum.toFixed(2));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table border="1">
<tr>
<th>sl</th>
<th>TA</th>
<th>DA</th>
</tr>
<tr>
<td>1</td>
<td><input class="expenses"></td>
<td><input class="expenses"></td>
</tr>
<tr>
<td>2</td>
<td><input class="expenses"></td>
<td><input class="expenses"></td>
</tr>
<tr>
<td>Total</td>
<td><input class="expenses_sum"></td>
<td><input class="expenses_sum"></td>
</tr>
</table>
This is when the "context" of the input that matters: you want to update the sum that is in the same column where the input element was updated.
What you can do is:
Get the index of the <td> element the input belongs to
Calculate the sum of all expenses belonging to the same column. This is done by filtering (using .filter()) all .expenses elements to ensure that their parent's <td> index matches that you've determined in step 2
Set the sum on the corresponding .expenses_sum element in the same column. This is again, done by filtering all .expenses_sum elements and only getting the one whose parent <td> index matches
Some additional pro-tips:
Listen to the onInput event. For input elements, that covers onKeyUp and onChange events, for convenience.
Use <input type="number" /> to prevent users from erroneously entering non-numerical characters
Use <input readonly /> on the .expenses_sum element, so that users don't fiddle with that sum by their own
Remember to cast the value of the input elements to a number. This can be done by using the + operator, i.e. +this.value. Remember that as per spec, all input elements, regardless their type, always has their value in type of string
Chain .each(calculateSum) to your original selection, so that you also compute the sum when the page is first loaded, i.e. $(".expenses").on('input', calculateSum).each(calculateSum);. This is very helpful when the .expenses elements might be pre-populated with values from the server-side (or if you have manually defined value="..."), for example.
See proof-of-concept below:
$(document).ready(function() {
$(".expenses").on('input', calculateSum).each(calculateSum);
});
function calculateSum() {
// Get the index of the parent `<td>` element
var cellIndex = $(this).closest('td').index();
// Get the values of expenses in the same column as the `<td>` element
var allExpensesInSameColumn = $('.expenses').map(function() {
if ($(this).closest('td').index() !== cellIndex)
return;
return +this.value;
}).get();
// Calculate the sum from returned array of values
var sumOfExpensesInSameColumn = allExpensesInSameColumn.reduce(function(acc, curVal) {
return acc + curVal;
});
// Set the sum on the `.expenses_sum` element in the corresponding column
$('.expenses_sum').each(function() {
if ($(this).closest('td').index() !== cellIndex)
return;
this.value = sumOfExpensesInSameColumn;
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table border="1">
<tr>
<th>sl</th>
<th>TA</th>
<th>DA</th>
</tr>
<tr>
<td>1</td>
<td><input class="expenses" type="number" /></td>
<td><input class="expenses" type="number" /></td>
</tr>
<tr>
<td>2</td>
<td><input class="expenses" type="number" /></td>
<td><input class="expenses" type="number" /></td>
</tr>
<tr>
<td>Total</td>
<td><input class="expenses_sum" readonly></td>
<td><input class="expenses_sum" readonly></td>
</tr>
</table>

JavaScript onBlur for multiple fields

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>

My attempt to grab the hrefs from a bunch of <a> tags: Explain where I'm going wrong

From a tbody element
<tbody id="results">
<tr>
<td><input type="checkbox">/../../Assets/Microsoft-Azure-roman_column.png</td>
<td>Microsoft</td>
<td>Azure</td>
<td>roman_column.png</td>
</tr>
<tr>
<td><input type="checkbox">/../../Assets/Microsoft-Azure-runphp.cmd</td>
<td>Microsoft</td>
<td>Azure</td>
<td>runphp.cmd</td>
</tr>
<tr>
<td><input type="checkbox">/../../Assets/Microsoft-Azure-runphp.cmd</td>
<td>Microsoft</td>
<td>Azure</td>
<td>runphp.cmd</td>
</tr>
<tr>
<td><input type="checkbox">/../../Assets/Microsoft-Azure-Picture1.png</td>
<td>Microsoft</td>
<td>Azure</td>
<td>Picture1.png</td>
</tr>
<tr>
<td><input type="checkbox">/../../Assets/Microsoft-Azure-vertical-align-scrnsht.png</td>
<td>Microsoft</td>
<td>Azure</td>
<td>vertical-align-scrnsht.png</td>
</tr>
<tr>
<td><input type="checkbox">/../../Assets/Microsoft-Azure-vertical-align-scrnsht.png</td>
<td>Microsoft</td>
<td>Azure</td>
<td>vertical-align-scrnsht.png</td>
</tr>
</tbody>
my procedure attempts to grab the hrefs and stick them in an array called links:
var resultRows = $('#results > tr > td > a');
for (var thisAnchor in resultRows) links.push($(this).attr('href'));
for (var thisLink in links) console.log(thisLink); // test
But that test is logging
0
1
.
.
.
171
172
to the console rather than the expected
/../../Assets/Microsoft-Azure-roman_column.png
/../../Assets/Microsoft-Azure-runphp.cmd
/../../Assets/Microsoft-Azure-runphp.cmd
/../../Assets/Microsoft-Azure-Picture1.png
/../../Assets/Microsoft-Azure-vertical-align-scrnsht.png
/../../Assets/Microsoft-Azure-vertical-align-scrnsht.png
Why is that and how do I fix it?
You could just use jQuery .each, like this:
$('tr').each(function() {
var href = $(this).find('a').attr('href');
links.push(href);
console.log(href);
});
Firstly, your HTML is invalid. You have an unclosed input tag.
Next your tbody needs to be wrapped by a table tag
Then if you are looking for an array of hrefs, you should use the jQquery.map function.
Here is a working example:
https://jsfiddle.net/p6h7o32m/
First, your selector was yeilding no elements, so change to
$('#results [href]')
Second, use .each instead of the for loop
$('#results [href]').each(function(){
links.push($(this).attr('href'));
});
Finally, change
for (var thisLink in links) console.log(thisLink);
to
for (var thisLink in links) console.log(links[thisLink]);
When you iterate a foreach loop in javascript like
for(var key in collection)
key, is the actual key or index in this case because you have an array
See it working here

How to add row in html table on top of specific row?

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.

Categories