while loop not iterating properly to remove table rows - javascript

Just trying to remove a table but loop is not removing all rows.
I have used alert to be sure it's the right element by id.
It does remove some rows but not all, just chunks.
console reports: DOM Exception 1,DOM Exception 8
function removeThis(unsetElement)
{ unsetElement.parentNode.removeChild(unsetElement); }

While you remove rows, their indices change; you need to do the loop from the top, i.e.
i=rowCounter-1;
while(i>=0){unsetTable.deleteRow(i);i--;}
Yet the better idea is just to purge the whole table; rows will be garbage-collected.

Another solution could be to use the special -1 index, which deletes the last row.
var i = thisTrAry.length;
while(i--) {
unsetTable.deleteRow(-1);
}
But if you remove the whole table anyway (in your last line) then there is no need to remove the rows first.

Related

Cypress - Assert only one element with a text exists

I have a table and I want to ensure that values are not repeated within a column using Cypress. Currently, I am doing
cy.get("#myTable")
.find(".table")
.contains("unique_value")
.should("exist")
This piece of code does check if a value in a column exists but it doesn't ensure that its the only entry with this value in the table. How do I check for uniqueness through Cypress?
Surprisingly, this
cy.get("#myTable")
.find(".table")
.contains("unique_value")
.should('have.length', 1);
or even this
cy.get("#myTable")
.find(".table td")
.contains("unique_value")
.should('have.length', 1);
will return a false positive - if you run it with two unique_value table cells it incorrectly passes.
Ref contains - yields indicates a single value is returned.
The best way I found was to shift the contains() up into the .find() selector,
cy.get("#myTable")
.find('.table td:contains("unique_value")')
.should('have.length', 1)
The above tests uniqueness between cells. If you want to also test the value within the cell, the simplest way is to invoke the text() method.
cy.get("#myTable")
.find('.table td:contains("unique_value")')
.should('have.length', 1) // ensure only one cell has value
.invoke('text')
.should('equal', 'unique_value') // check the exact content of the cell
See the first example on this page Assertions
sorry about the previous answer, I forgot with .contains it selects sorts out 1 element from the found list. anyway, there are two ways to do this.
1st :
it'll look like,
cy.get(".table")
.find(('td:contains("unique_value")'))
.should('have.length', 1)
Note: This might be problematic if the same table cell has repetitive unique_value
For example: Let's say you are expecting a unique id (1234) in a table cell, but the table looks as follows
<tr>
<td>1234, 1234<td>
<td>value<td>
<tr>
If we take this scenario, the above solution will make the test as passed even though the unique id is repeated in the same cell. If you want to validate those kinds of scenarios too, I think the best solution would be,
cy.get(".table")
.then($el => {
expect($el[0].innerText.split('unique_value').length).to.equal(2)
})
in this case, if the table does not contain unique_value the array length will be 1 and if it has more than 1 unique_value the array length will be more than 2 so, this will work with any string, paragraph, table, etc.
cheers.

Cloning last row in ag grid

I am missing something, yet.. I have ad grid, and can't figure out, how to clone last row.
Here is snippet of what I try to do:
lastrow = gridOptions.api.getDisplayedRowAtIndex(
gridOptions.api.getDisplayedRowCount() - 1
);
gridOptions.api.updateRowData({ add: [lastrow] });
optionally I tried:
gridOptions.api.updateRowData({ add: lastrow });
but that doesn't work neither.
I am also unable to access cell value by column name, like
window.alert(lastrow["1"])
"1" is valid field name.
What am I doing wrong?
I must also mention, that
firstrow = gridOptions.api.getDisplayedRowAtIndex(0);
gridOptions.api.setRowData(firstrow);
kinda works,but resets all rows, and I need to clone last row, not delete all rows, besides last.
Thanks in advance.
So based on docs, you are able to get RowNode by the index:
getDisplayedRowAtIndex(index) Returns the displayed rowNode at the given index.
keep in mind, it will return RowNode - not RowNode.data
And to get the last index you just need to use another method:
getLastDisplayedRow() Get the index of the last displayed row due to scrolling (includes not visible rendered rows in the buffer)
now once you know how to get RowNode you just need to execute updateRowData with node.data
P.S. you need to use RowNode.data - instead of RowNode itself.
Here is a code:
let lastrow = this.gridApi.getDisplayedRowAtIndex(this.gridApi.getLastDisplayedRow());
this.gridApi.updateRowData({ add: [lastrow.data] });
And here is a demo
There is a api method for getting the index of the last displayed row,
can use that index to get the row.
lastRowIndex = gridOptions.api.getLastDisplayedRow();
lastRow = gridOptions.api.getDisplayedRowAtIndex(lastRowIndex);
Not sure if that accomplishes everything you are trying to do, but based off the question this will get the last displayed row.

removing element from parent node with loop

today i've got this struggle to solve, so i have a array of html elements (e.g 3 inputs)
and i want to delete every single one from the dom. so i must iterate loop over them but i also should not increment the value because it will skip every other elements and that means i must only delete first element of array until it exists, so for this task i use this code
while(inputs[0]) {
inputs[0].parentNode.removeChild(inputs[0]);
}
and this works perfectly and removes all elements.
but what about for...of loop? it also gets every value of array and what if i just delete first input every time it's getting a element from array ? like this:
for(input of inputs){
inputs[0].parentNode.removeChild(inputs[0]);
}
i also tried this and in the 3 inputs it left third one (did not delete it)
so i want to know why? can someone show me how it missed third one? (graphical explanation will be the best)
Thank You
At the first iteration, the iterator is at position zero, there are three elements. You delete one.
v
0 1 2
At the second iteration, the iterator is at position one, there are two elements. You delete one.
v
0 1
At the third iteration, the iteration stops, as there is only one element, and the index is at three, so it is outside of the array. No delete operation is done.
v
0
The main problem/advantage here is that nodes is a live collection. If it would not be live (e.g. if you use querySelectorAll), then the second version would work:
// v declare variables!
for(const input of document.querySelectorAll("input"))
input.remove(); // < remove is way easier

Appending all the tables in a div onto the body

i have a div, with 3 tables in it.
var x = tempDiv.getElementsByClassName("hiscore_table");
I know this for sure because when i console log it, it prints like this:
I make a new div to append the tables on
var newDiv = document.createElement('div');
for (let i = 0; i < x.length; i++) {
newDiv.appendChild(x[i]);
}
I then append to the body, but only 2 tables show. I debugged the for loop and its only running the loop 2 times. If i print x.length i get 3. Im not too good at debugging but when i append child it seems to be deleting it from the old div, maybe thats the cause.
You’re creating a new <div> and appending elements that currently exist in the DOM to it. This means that you’re removing those elements from the DOM in order to append them to the <div> (which is not in the DOM).
Next, the thing you need to know about HTMLCollections (the return value of document.getElementsByClassName) is that they’re a live list. This means that any changes to the DOM are immediately reflected in the collection.
So, i is 0, you append the first element, your collection now only contains two elements.
Next, i is 1, you append the second element of your remaining collection, which is the third element overall. Only one element remains in the collection.
Next, i is 2, which is out of bounds for your now-one-element collection.
This is similar to removing items from an HTMLCollection.
There are a few approaches to solve this, like iterating in reverse order. But I prefer a functional approach:
Array.from(x).forEach((table) => newDiv.appendChild(table));
This converts the HTMLCollection to an array right away, so it’s no longer a live list.
Just for completeness, if you want to support older browsers without the need for pollyfills or similar (i.e. write robust, easily maintained code), you can use a while loop:
while (x[0]) {
newDiv.appendChild(x[0]);
}
Oh, another simple fix is to use querySelectorAll, which returns a static NodeList:
var x = tempDiv.querySelectorAll(".hiscore_table").

jQuery on page load sorting will not sort with leading currency symbol

In my previous question I was trying to sort a table on page load without any client side table sorting toggle switches just so the table would be sorted for a user as they arrive on the page.
The question was answered and I got a pretty good response and thought i'd solved the issue so I went to sleep, so as I tried to use the code on my website today I realized the sorting technique is not working but works perfectly in jsfiddle https://jsfiddle.net/ghzch66e/12/.
So I then realized the table wont sort on my website because on the webpage the data contains a leading (£) symbol https://jsfiddle.net/ghzch66e/13/.
How can I make the table sort even with a leading (£) symbol.
jQuery(document).ready(function(e) {
var dataRows = [];
//Create an array of all rows with its value (this assumes that the amount is always a number. You should add error checking!! Also assumes that all rows are data rows, and that there are no header rows. Adjust selector appropriately.
$('#internalActivities > tbody > tr').each(function(i,j) {
dataRows.push({'amount': parseFloat($(this).find('.amount').text()), 'row': $(this)});
})
//Sort the data smallest to largest
dataRows.sort(function(a, b) {
return a.amount - b.amount;
});
//Remove existing table rows. This assumes that everything should be deleted, adjust selector if needed :).
$('#internalActivities').empty();
//Add rows back to table in the correct order.
dataRows.forEach(function(ele) {
$('#internalActivities').append(ele.row);
})
});
replace the "£" with "" when pushing it to the array
$('#internalActivities > tbody > tr').each(function(i,j) {
dataRows.push({'amount': parseFloat($(this).find('.amount').text().replace(/£/,"")), 'row': $(this)});
})

Categories

Resources