Cypress iterating through table assert two columns - html-table

I have a simple table e.g.:
<table>
<tr>
<td>name 1</td>
<td>name 2</td>
<tr>
<tr>
<td>name 3</td>
<td>name 4</td>
<tr>
</table>
With cypress I want to verify, that name 1 and name 2 are not present in the table (but only if they are next to each). If name 1 is alone in any td, then it is ok, so only if name 1 and name 2 are in one table row.
I tried to iterate through table via:
verifyTable(child, parent) {
cy.get("table tr").each(($el, index, $list) => {
cy.get("tr").eq(index).find("td:nth(0)").should('not.contain',child);
cy.get("tr").eq(index).find("td:nth(1)").should('not.contain',parent);
})
}
This is working fine, but if it finds child in first column, it fails and doesn't check the next column. The same if the element doesn't exists in first column but exists only in second column, it fails.
It should fail only if child and parent exists next to each other. I am not sure how to connect both conditions.
Even if I used chaning with AND, if it finds the first element, it fails:
cy.get("tr").eq(index).should('not.contain',child).and('not.contain',parent);

You can substitute jQuery expressions when checking the cells, they won't fail the test if not found.
Then test the combination - I think I have the right logic, but you may need to adjust if I misunderstood.
verifyTable(child, parent) {
cy.get("table tr").each(($tr, index, $list) => {
const childExists = $tr.find(`td:nth(0):contains(${child})`).length;
const parentExists = $tr.find(`td:nth(1):contains(${parent})`).length;
expect(!childExists || !parentExists).to.eq(true)
// or this is the same, but may be closer to your specified requirement
expect(!(childExists && parentExists)).to.eq(true)
})
}

Related

How to use variable in the array name

I am building a calendar view of assigned tasks, with an array controlling which tasks should display in each day's cell. I need to reference a varying array key in the v-for loop, but can't find the proper syntax.
My dataset (for tasks on the 5th and 6th of the month) is:
assignments: {
'05':
[
'task one',
'task two'
],
'06':
[
'task three',
'task four'
]
},
This hard-coding to day ['05'] works as I'd like:
<tbody id="calendar-table">
<tr>
<td v-for="(day, index) in calendar.days_array" v-if="index < 7">
<table>
<tr>
{{day}}
</tr>
<tr v-for="task_name in condensedAssignments['05']">
<td>
{{task_name}}
</td>
</tr>
</table>
</td>
</tr>
This gets the attached screenshot:
calendar with tasks within all days
I want to replace the '05' in the second loop with the contents of the variable "day" of the first loop. Variations on v-for="task_name in assignments[{{day}}]" are rejected. I've looked into computed properties or methods, but haven't found a way to pass the current iteration's "day" into them.
How do I get the inner loop to recognize the "day" of the outer loop?
You can use the variable name as index for your condensedAssignments variable, but, I think it can't work because the index is a string and the variable day is a number.
You can do this:
<tr v-for="task_name in condensedAssignments[String(day).padStart(1, '0')]">
<td>{{task_name}}</td>
</tr>
String(day) -> Cast variable to a string
.padStart(2, '0') -> Add one zero at left because your index is '05' then two chars long
Actually, you have several problems here.
First, you should not use v-if and v-for on the same element. If you only want the first n elements, a solution could be to use the slice method : calendar.days_array.slice(0, 7)
The second anomaly is that your assignments variable isn't an Array but an Object. You can search how to iterate through an object or check this Digital Ocean tutorial.
Also, you can call the second v-for statement on your variable instead of harcoding your taskname.
It may looks something like this :
<td v-for="(day, key, i) in calendar.days_array">
<tr>{{ key }}</tr>
<tr v-for="task_name in day">
{{ task_name }}
</tr>
</td>
Thank you to fdisotto for the quick answer. I tried again using a method in the meantime, and was reminded that I have another issue: My "day" field is sometimes null. I was able to get it working, though, with this method:
daysTasks: function(day){
if (!day) {return []};
if (String(day).length < 2) {
day = '0'+day;
}
return this.assignments[day];
},
and this template:
<td v-for="(day, index) in calendar.days_array" :key='day' v-if="index < 7">
<table>
<tr>
{{day}}
</tr>
<tr v-for="task_name in daysTasks(day)" :key='task_name'>
<td>{{task_name}}
</td>
</tr>
Now, only the 5th of the month sees the first two tasks, and the 6th sees the last two.

how to apply filter on JQuery DataTable each columns? [duplicate]

I'm trying to filter table rows in an intelligent way (as opposed to just tons of code that get the job done eventually) but a rather dry of inspiration.
I have 5 columns in my table. At the top of each there is either a dropdown or a textbox with which the user may filter the table data (basically hide the rows that don't apply)
There are plenty of table filtering plugins for jQuery but none that work quite like this, and thats the complicated part :|
Here is a basic filter example http://jsfiddle.net/urf6P/3/
It uses the jquery selector :contains('some text') and :not(:contains('some text')) to decide if each row should be shown or hidden. This might get you going in a direction.
EDITED to include the HTML and javascript from the jsfiddle:
$(function() {
$('#filter1').change(function() {
$("#table td.col1:contains('" + $(this).val() + "')").parent().show();
$("#table td.col1:not(:contains('" + $(this).val() + "'))").parent().hide();
});
});
Slightly enhancing the accepted solution posted by Jeff Treuting, filtering capability can be extended to make it case insensitive. I take no credit for the original solution or even the enhancement. The idea of enhancement was lifted from a solution posted on a different SO post offered by Highway of Life.
Here it goes:
// Define a custom selector icontains instead of overriding the existing expression contains
// A global js asset file will be a good place to put this code
$.expr[':'].icontains = function(a, i, m) {
return $(a).text().toUpperCase()
.indexOf(m[3].toUpperCase()) >= 0;
};
// Now perform the filtering as suggested by #jeff
$(function() {
$('#filter1').on('keyup', function() { // changed 'change' event to 'keyup'. Add a delay if you prefer
$("#table td.col1:icontains('" + $(this).val() + "')").parent().show(); // Use our new selector icontains
$("#table td.col1:not(:icontains('" + $(this).val() + "'))").parent().hide(); // Use our new selector icontains
});
});
This may not be the best way to do it, and I'm not sure about the performance, but an option would be to tag each column (in each row) with an id starting with a column identifier and then a unique number like a record identifier.
For example, if you had a column Produce Name, and the record ID was 763, I would do something like the following:
​​<table id="table1">
<thead>
<tr>
<th>Artist</th>
<th>Album</th>
<th>Genre</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td id="artist-127">Red Hot Chili Peppers</td>
<td id="album-195">Californication</td>
<td id="genre-1">Rock</td>
<td id="price-195">$8.99</td>
</tr>
<tr>
<td id="artist-59">Santana</td>
<td id="album-198">Santana Live</td>
<td id="genre-1">Rock</td>
<td id="price-198">$8.99</td>
</tr>
<tr>
<td id="artist-120">Pink Floyd</td>
<td id="album-183">Dark Side Of The Moon</td>
<td id="genre-1">Rock</td>
<td id="price-183">$8.99</td>
</tr>
</tbody>
</table>
You could then use jQuery to filter based on the start of the id.
For example, if you wanted to filter by the Artist column:
var regex = /Hot/;
$('#table1').find('tbody').find('[id^=artist]').each(function() {
if (!regex.test(this.innerHTML)) {
this.parentNode.style.backgroundColor = '#ff0000';
}
});
You can filter specific column by just adding children[column number] to JQuery filter. Normally, JQuery looks for the keyword from all the columns in every row. If we wanted to filter only ColumnB on below table, we need to add childern[1] to filter as in the script below. IndexOf value -1 means search couldn't match. Anything above -1 will make the whole row visible.
ColumnA | ColumnB | ColumnC
John Doe 1968
Jane Doe 1975
Mike Nike 1990
$("#myInput").on("change", function () {
var value = $(this).val().toLowerCase();
$("#myTable tbody tr").filter(function () {
$(this).toggle($(this.children[1]).text().toLowerCase().indexOf(value) > -1)
});
});
step:1 write the following in .html file
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names..">
<table id="myTable">
<tr class="header">
<th style="width:60%;">Name</th>
<th style="width:40%;">Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Germany</td>
</tr>
<tr>
<td>Berglunds snabbkop</td>
<td>Sweden</td>
</tr>
<tr>
<td>Island Trading</td>
<td>UK</td>
</tr>
<tr>
<td>Koniglich Essen</td>
<td>Germany</td>
</tr>
</table>
step:2 write the following in .js file
function myFunction() {
// Declare variables
var input, filter, table, tr, td, i;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
// Loop through all table rows, and hide those who don't match the search query
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}

How to hide a column in dynamic Material table in Angular 6?

I have the following dynamic Angular material 6 tables.
<table mat-table [dataSource]="animalDataSource" matSort *ngIf="animal && animal.length > 0">
<ng-container *ngFor="let disCol of animalColumns;" matColumnDef="{{disCol}}">
<th mat-header-cell *matHeaderCellDef mat-sort-header >{{disCol}}</th>
<td mat-cell *matCellDef="let rowValue;">{{rowValue[disCol]}}
<button *ngIf="disCol == 'Action'" mat-mini-fab class="delete-icon" (click)="deleteAnimalData(rowValue)">
<mat-icon>delete</mat-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="animalColumns"></tr>
<tr mat-row *matRowDef="let rowdata; columns: animalColumns;"></tr>
</table>
And here's my script:
this.animals = [];
this.animalColumns = [];
for (var i in animalList) {
this.animal = {
"Id": animalList[i]["_id"],
"Animal": animalList[i].name,
"Created By": animalList[i].createdBy,
"Created On": new Date(animalList[i].dateOfEntry)
}
this.animals.push(this.animal);
}
this.animalDataSource = new MatTableDataSource(this.animals);
for (let displayColName in this.animals[0]) {
this.animalColumns.push(displayColName);
}
this.animalColumns.push("Action");
There are 4 columns in the table. And I don't need the 'Id' column to be displayed in the table. I have tried giving *ngIf and [style.display]='none'. Both are hiding the column with the full-length gap between the columns.
I could have removed the 'Id' field from the object, but I need the value of the 'Id' column when the user clicks on the delete button[method: deleteAnimalData(rowValue)].
Please suggest me, without removing the 'ID' key from the object, how I can hide the column.
The way I was able to make it work is by having an array of objects(say animalObjects) that define all the table columns building the template.
Once they are all defined I have another array that has the name of the columns (animalColumns) to be displayed.
When you need to hide a column then you can remove the item from the 2nd array (animalColumns) while leaving the first (animalObjects) untouched.
You basically have to create the table with all the columns, then update the displaycolumn property with the modified animalColumn array.
stackblitz example here
Just do NOT add the ID to animalColumns, as this array is what defines your columns. See columns: animalColumns in your HTML

yadcf remove select option before exFilterColumn()

I am trying to remove a select option from an external filter select field using yadcf 0.8.9. In yadcf 0.6.9 I was able to remove this option before the call to exFilterColumn(), but in 0.8.9 I must remove the option after the call.
Actually what I am trying to do is force the select to have some value which is in the table column, and to have the table filtered on that value
I can't seem to figure out how to remove the unfiltered possibility from the select and have the table filtered on the chosen value (either the first or one I am picking in the code). In 0.6.9, I removed '-1' value option, but this doesn't seem to work in 0.8.9.
Advice?
See http://codepen.io/louking/pen/ZWYpGM vs http://codepen.io/louking/pen/zqxBLL
html:
<div>
<span id='yadcfext'></span>
</div>
<table id=tbl>
<thead>
<tr>
<th>col0</th>
<th>col1</th>
<th>col2</th>
</tr>
</thead>
<tbody>
<tr>
<td>a0</td>
<td>b0</td>
<td>c0</td>
</tr>
<tr>
<td>a1</td>
<td>b1</td>
<td>c1</td>
</tr>
</tbody>
</table>
remove option before exFilterColumn
var dt= $('#tbl')
.dataTable()
.yadcf([
{column_number: 0,
filter_container_id: 'yadcfext'}
]);
var selectfilter = '#yadcfext';
$(selectfilter + ' option[value="-1"]').remove();
yadcf.exFilterColumn(dt, [[0,'a1']]);
remove option after exFilterColumn()
var dt= $('#tbl')
.dataTable()
.yadcf([
{column_number: 0,
filter_container_id: 'yadcfext'}
]);
yadcf.exFilterColumn(dt, [[0,'a1']]);
var selectfilter = '#yadcfext';
$(selectfilter + ' option[value="-1"]').remove();
Sounds like a new feature :)
So since 0.9.0.beta.9 you can use the ommit_default_label option, see your codepen in action
* omit_default_label
Required: false
Type: boolean
Default value: false
Description: Prevent yadcf from adding "default_label" (Select value / Select values)
Note Currently supported in select / multi_select / custom_func / multi_select_custom_func

grid.selection.getSelected().length on selecting one row

I have created a dojox.grid.DataGrid and i want to perform some operations on the rows selected by the user, so, i have placed an alert to get the no. of rows selected by the user.
I am using :
var noofrows=grid.selection.getSelected().length;
alert(noofrows);
to get the number of rows selected by the user in the grid.
When the user selects one row the above statement alerts 0 but it should pop-up 1 as 1 row is selected by user.
When user selects multiple rows it pop-ups the correct number of rows selected by the user.
After selecting multiple rows(right result is getting poped-up) when user selects one row it pop-ups the correct output i.e.: 1.
So, basically the issue is when user selects one row for the first time it pop-ups the wrong output(i.e :0).
Here is the grid creation code :
<table id="AA.FavouritesGrid" dojoType="dojox.grid.DataGrid"
region="center"
jsId="table"
id="table"
store="AAFavouritesStore" style="font-size:30px;width:100%;padding:0px;display:0px;">
<thead>
<tr>
<%
String userCode ="";
userCode = request.getUserPrincipal().getName();
try {
Map<String,String> columnNameLabelMap=model.getDynamicNameLabelmap("Favourites", userCode, locale);
// Loop round columns ordered by user
for (Map.Entry<String, String> entry : columnNameLabelMap.entrySet()){
int width = columnDataById.get(entry.getKey()).getWidth();
columnDataById.remove(entry.getKey());
%>
<th field=<%=entry.getKey() %> width="<%=width%>" height="22px" nowrap="nowrap"><%=entry.getValue()%></th>
<%
}
} catch (Exception e) {
System.out.println(e);
}
// Present any left over columns in default order
for (ColumnData entry : columnDataById.values()){
%>
<th field=<%=entry.getId() %> width="<%=entry.getWidth()%>" height="22px" nowrap="nowrap"><%=entry.getName()%></th>
<%
}
%>
<th field="path" hidden="true"></th>
<th field="underwritingYear" hidden="true" ></th>
<th field="lpRCTLobDesc" hidden="true" ></th>
<th field="lpRCTLob" hidden="true" ></th>
</tr>
</thead>
</table>
favContextMenu = dojo.connect(dijit.byId("AA.FavouritesGrid"),"onCellContextMenu", favouritesGridOnContextMenu );
function favouritesGridOnContextMenu(e) {
alert(table.selection.getSelected().length);
}
Please help to resolve the problem
Thanks
Try below 2 ways to get selected item and items.
var e = dijit.byId("addressMapStoreGrid");
if (e.focus.rowIndex < 0) {
alert('Please select one row!');
return;
}
-
var items = grid.selection.getSelected();