I have ajax table in my web and this table has many pages. My goal is to go through all the rows and columns, go to the next page and make the following procedure until the end of the page. I have the following code:
for(let i = 0; i < 10; i++){
cy.get('tr:has(td)').each(($tr, rowIndex) => { // look at each row individually
cy.wrap($tr)
.find('td') // all cols inside this row
.invoke('slice', 5, 8) // filter to last 3 cols only
.invoke('text') // get all the text in one lump
.then(text => {
if (text.trim() === '') { // after trim(), is all text empty?
console.log(`Row ${rowIndex+1} has three empty cols`)
cy.wrap($tr).find('td').eq(5).click({force: true}) // click the 6th col
cy.wait(4000)
cy.get('.review-modal_textarea_3L5AQ').eq(0).should('be.visible').type(str)
cy.get('.pagination_pagination_2iOOV > :nth-child(4)').click({force: true}) //clicking to the next page
}
I managed to go through all rows and columns in one page, but having problem going to the next page (its going just one time). I think I have problem with loop. It simply doesn't working. I have i<10 because I have 10 pages, but the pages can be more (may there is a way to do it without for loop). How can I solve this problem?
I think you can do it by wrapping the per-page code in a function and calling it at the right time.
The trouble with for(let i = 0; i < 10; i++){ it's not letting the page change complete.
function handlePage() { // naf function name, but for illustration
cy.get('tr').each(($tr, rowIndex) => { // look at each row individually
cy.wrap($tr)
.find('td') // all cols inside this row
.invoke('slice', 5, 8) // filter to last 3 cols only
.invoke('text') // get all the text in one lump
.then(text => {
if (text.trim() === '') { // after trim(), is all text empty?
console.log(`Row ${rowIndex+1} has three empty cols`)
cy.wrap($tr).find('td').eq(5).click() // click the 6th col
cy.wait(4000)
cy.get('.review-modal_textarea_3L5AQ').eq(0).should('be.visible').type(str)
}
})
})
}
cy.visit(...) // whatever gets 1st page
handlePage() // 1st page
Cypress._.times(9, () => { // 9 more pages
cy.get('.pagination_pagination_2iOOV > :nth-child(4)').click({force: true})
.then(() => { // after page transition
// may need a cy.wait() or test page number on screen
handlePage()
})
})
Related
I´ve accomplished the react drag and drop functionality into my project so i can reorder a row in a react table´s list. The problem is i have a column named 'Sequence', witch shows me the order of the elements, that i can´t update its values.
Example:
before (the rows are draggable):
Sequence | Name
1 Jack
2 Angel
after ( i need to update the values of Sequence wherea i change their position after dropping a specific draggable row, in this case i dragged Jack at the first position and dropped it at the second position) :
Sequence | Name
1 Angel
2 Jack
React/Redux it´s allowing me to change the index order of this array of elements, without getting the 'A state mutation was detected between dispatches' error message, but is not allowing me to update the Sequence values with a new order values.
This is what i have tried so far:
// within the parent class component
// item is an array of objects from child
UpdateSequence(startIndex, endIndex, item) {
// the state.Data is already an array of object
const result = this.state.Data;
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
// this is working without the mutation state error
this.setState({ Data: result })
let positionDiff = 0;
let direction = null;
let newIndex = 0;
positionDiff = endIndex - startIndex;
if (startIndex > endIndex) {
direction = "up";
}
else if (startIndex < endIndex) {
direction = "down";
}
if (positionDiff !== 0) {
for (var x = 0; x <= Math.abs(positionDiff); x++) {
if (x === 0) {
newIndex = startIndex + positionDiff - x;
this.setState(prevState => ({
Data: {
...prevState.Data,
[prevState.Data[newIndex].Sequence]: Data[newIndex].Sequence + positionDiff
},
}));
}
else {
if (direction === "down") {
newIndex = startIndex + positionDiff - x;
this.setState(prevState => ({
Data: {
...prevState.Data,
[prevState.Data[newIndex].Sequence]: Data[newIndex].Sequence - 1
},
}));
}
else if (direction === "up") {
Data= startIndex + positionDiff + x;
this.setState(prevState => ({
Data: {
...prevState.Data,
[prevState.Data[newIndex].Sequence]: Data[newIndex].Sequence + 1
},
}));
}
}
}
// so when i call save action i am stepping into the 'A state mutation was detected between dispatches' error message.
this.props.actions.saveSequence(this.state.Data)
.then(() => {
this.props.actions.loadData();
})
.catch(error => {
toastr['error'](error, 'error....');
})
}
Calling the action 'saveSequence' whenever i try to update the element of the array, 'Sequence', i am getting the 'A state mutation was detected between dispatches' error message.
Any help will be greatfull! Thank you!
note: The logic applied to reorder the Sequence is ok.
While I don't know redux particularly well, I am noticing that you are directly modifying state, which seems like a likely culprit.
const result = this.state.Data;
const [removed] = result.splice(startIndex, 1);
splice is a destructive method that modifies its input, and its input is a reference to something in this.state.
To demonstrate:
> state = {Data: [1,2,3]}
{ Data: [ 1, 2, 3 ] }
> result = state.Data.splice(0,1)
[ 1 ]
> state
{ Data: [ 2, 3 ] }
Notice that state has been modified. This might be what Redux is detecting, and a general React no-no.
To avoid modifying state, the easy way out is to clone the data you are looking to modify
const result = this.state.Data.slice()
Note that this does a shallow copy, so if Data has non-primitive values, you have to watch out for doing destructive edits on those values too. (Look up deep vs shallow copy if you want to find out more.) However, since you are only reordering things, I believe you're safe.
Well, i figured it out changing this part of code:
//code....
const result = item;
const [removed] = result.splice(startIndex, 1);
// i created a new empty copy of the const 'removed', called 'copy' and update the Sequence property of the array like this below. (this code with the sequence number is just a sample of what i came up to fix it )
let copy;
copy = {
...removed,
Sequence: 1000,
};
result.splice(endIndex, 0, copy);
After i didn´t setState for it, so i commented this line:
// this.setState({ Data: result })
//...code
and the end of it was putting the result to the save action as a parameter , and not the state.
this.props.actions.saveSequence(result)
Works and now i have i fully drag and drop functionality saving the new order sequence into the database with no more 'A state mutation was detected between dispatches' error message!
Anyone please tell me how can i select next consecutive row from first page to second page of my kendo grid and reverse back to the previous page ? Kendo Grid API just only gives me information on 'select' and from there I have no clue at all how to implement my desired selection. What I have now is only selecting the row of the selected/active cell. Any insight/references are also appreciated. So far I haven't came across with any examples or article.
var data = $("#grid").data('kendoGrid');
var arrows = [38,40];
data.table.on("keydown", function (e) {
if (arrows.indexOf(e.keyCode) >= 0) {
setTimeout(function () {
data.clearSelection();
data.select($("#grid_active_cell").closest("tr"));
},1);
}
});
http://dojo.telerik.com/eSUQO
var data = $("#grid").data('kendoGrid');
var arrows = [38,40];
var navrow_uid; ** add this tracking variable;
data.table.on("keydown", function (e) {
if (arrows.indexOf(e.keyCode) >= 0) {
setTimeout(function () {
data.clearSelection();
// break this up
// data.select($("#grid_active_cell").closest("tr"));
// fetch next row uid and compare to tracker
var nextrow = $("#grid_active_cell").closest("tr");
var uid = nextrow.data('uid');
if (navrow_uid == uid ) {
console.log("last navigable row");
data.dataSource.page(1+data.dataSource.page());
// best option here would be to set auto-page flag for databound event handler
} else {
data.select(nextrow);
navrow_uid = uid;
}
},1);
}
});
You will want to add a grid data bound handler, and have that check the aut-page flag to see if you need to select first or last row of page.
I have line chart where I need to show frequency of order executions over the course of a day. These orders are grouped by time interval, for example every hour, using custom reduce functions. There could be an hour interval when there were no order executions, but I need to show that as a zero point on the line. I create a 'fake group' containing all the bins with a zero count...and the initial load of the page is correct.
However the line chart is one of 11 charts on the page, and needs to be updated when filters are applied to other charts. When I filter on another chart, the effects on this particular frequency line chart are incorrect. The dimension and the 'fake group' are used for the dc.chart.
I put console.log messages in the reduceRemove function and can see that there is something wrong...but not sure why.
Any thoughts on where I could be going wrong.
FrequencyVsTimeDimension = crossfilterData.dimension(function (d) { return d.execution_datetime; });
FrequencyVsTimeGroup = FrequencyVsTimeDimension.group(n_seconds_interval(interval));
FrequencyVsTimeGroup.reduce(
function (p, d) { //reduceAdd
if (d.execution_datetime in p.order_list) {
p.order_list[d.execution_datetime] += 1;
}
else {
p.order_list[d.execution_datetime] = 1;
if (d.execution_type !== FILL) p.order_count++;
}
return p;
},
function (p, d) { //reduceRemove
if (d.execution_type !== FILL) p.order_count--;
p.order_list[d.execution_datetime]--;
if (p.order_list[d.execution_datetime] === 0) {
delete p.order_list[d.execution_datetime];
}
return p;
},
function () { //reduceInitial
return { order_list: {}, order_count: 0 };
}
);
var FrequencyVsTimeFakeGroup = ensure_group_bins(FrequencyVsTimeGroup, interval); // function that returns bins for all the intervals, even those without data.
This is my first time working with Kendo UI. I have a Kendo UI grid with child nodes. I want to retain the expanded rows after databinding. Right now its getting collapsed after a row is added in the child
I have tried suggestion from here
dataBound: function() {
this.expandRow(this.tbody.find("tr.k-master-row").first());
}
But this expands the first row only.
How to retain rows? What am I missing?
Codepen
After a lot of playing around with your code example in CodePen, I believe I've come up with an elegant solution that works.
Having worked with Kendo UI for over three years, I've become pretty familiar with some of its inner workings. As such, I'm going to take advantage of one of these - the data-uid attribute. Kendo UI puts these on all <tr> elements in its grid. I chose this attribute because I know that when we call grid.expandRow() we're going to need to fashion a valid jQuery selector to pass in as a parameter. This eliminates the need for us to add our own attributes or classes and the code to handle them.
First, we need to define a variable to hold our row reference. We'll call it expandedRowUid. To set its value, we hook into the detailExpand event of the grid. So, when the user expands a row, we store its data-uid number.
var expandedRowUid;
var grid = $('#grid').kendoGird({
// ...
detailExpand: function(e) {
expandedRowUid = e.masterRow.data('uid');
}
});
Then, whenever a change is made that causes the master grid to re-bind to its data, we hook into the dataBound event of the grid and re-expand the row that has a data-uid equal to the one stored in expandedRowUid.
var grid = $('#grid').kendoGird({
// ...
detailExpand: function(e) {
expandedRowUid = e.masterRow.data('uid');
},
dataBound: function() {
this.expandRow($('tr[data-uid=' + expandedRowUid + ']'));
}
});
Here is the working CodePen example.
NOTE: This will only re-expand the last row that was expanded before the data bind is triggered. So, if you expand rows 4, 5, and 2 in that order, and then trigger a data bind, only row 2 will be re-expanded. You can obviously extend this functionality to handle use cases like that though.
GridDetailExpand: function (e) {
var gridId = e.sender.element[0].id;
var grid = $("#" + gridId).data("kendoGrid");
var data = grid.dataItem(e.masterRow);
addToArray(expandedRows, data.UniqueIdOfYourDataInGrid);
},
GridDetailCollapse: function (e) {
var gridId = e.sender.element[0].id;
var grid = $("#" + gridId).data("kendoGrid");
var data = grid.dataItem(e.masterRow);
removeFromArray(expandedRows, data.UniqueIdOfYourDataInGrid);
}
And then on databound
var gridId = e.sender.element[0].id;
var grid = $("#" + gridId).data("kendoGrid");
$.each(grid.tbody.find('tr.k-master-row'), function () {
var data = grid.dataItem(this);
if (isInArray(expandedRows, data.UniqueIdOfYourDataInGrid)) {
grid.expandRow(this);
}
});
Functions required:
var expandedRows = [];
function addToArray(arr, value) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] === value) return;
}
arr.push(value);
}
function removeFromArray(arr, value) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] === value) {
delete arr[i];
return;
}
}
}
function isInArray(arr, value) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] === value) return true;
}
return false;
}
Hope this helps ... took me a while to figure it out...
Solution for Retaining Last Expanding row in the parent grid after records added in the child grid get refreshed.
detailInit: function (e) {
//Get Parent Grid Last expanded Row index
lastRowIndex = $(e.masterRow).index(".k-master-row");
},
dataBound: function () {
//Check any parent grid row is expanded based on row index
if (lastRowIndex != null && lastRowIndex != undefined){
//find the Grid row details based on row index
var row = $(this.tbody).find("tr.k-master-row:eq(" + lastRowIndex + ")");
//If expand Row exists then it will expanded
this.expandRow(row);
}
else {
//None of the Parent Grid row is expanded then,default First row is expanded
this.expandRow(this.tbody.find("tr.k-master-row").first());
}
}
Please help to solve this very annoying problem. I am using a for loop to iterate over an array of data and create multiple grids. It is working well but the filter function is not binding properly (it only binds to the LAST grid created) Here is the code:
// this function iterates over the data to build the grids
function buildTables() {
// "domain" contains the dataset array
for (i = 0; i < domains.length; i++) {
var dataView;
dataView = new Slick.Data.DataView();
var d = domains[i];
grid = new Slick.Grid('#' + d.name, dataView, d.columns, grids.options);
var data = d.data;
// create a column filter collection for each grid - this works fine
var columnFilters = columnFilters[d.name];
// this seems to be working just fine
// Chrome console confirms it is is processed when rendering the filters
grid.onHeaderRowCellRendered.subscribe(function (e, args) {
$(args.node).empty();
$("<input type='text'>")
.data("columnId", args.column.id)
.val(columnFilters[args.column.id])
.appendTo(args.node);
});
// respond to changes in filter inputs
$(grid.getHeaderRow()).delegate(":input", "change keyup", function (e) {
var columnID = $(this).data("columnId");
if (columnID != null) {
// this works fine - when the user enters text into the input - it
// adds the filter term to the filter obj appropriately
// I have tested this extensively and it works appropriately on
// all grids (ie each grid has a distinct columnFilters object
var gridID = $(this).parents('.grid').attr('id');
columnFilters[gridID][columnID] = $.trim($(this).val());
dataView.refresh();
}
});
//##### FAIL #####
// this is where things seem to go wrong
// The row item always provides data from the LAST grid populated!!
// For example, if I have three grids, and I enter a filter term for
// grids 1 or 2 or 3 the row item below always belongs to grid 3!!
function filter(row) {
var gridID = $(this).parents('.grid').attr('id');
for (var columnId in grids.columnFilters[gridID]) {
if (columnId !== undefined && columnFilters[columnId] !== "") {
var header = grid.getColumns()[grid.getColumnIndex(columnId)];
//console.log(header.name);
}
}
return true;
}
grid.init();
dataView.beginUpdate();
dataView.setItems(data);
dataView.setFilter(filter); // does it matter than I only have one dataView instance?
dataView.endUpdate();
grid.invalidate();
grid.render();
In summary, each function seems to be binding appropriately to each grid except for the filter function. When I enter a filter term into ANY grid, it returns the rows from the last grid only.
I have spent several hours trying to find the fault but have to admit defeat. Any help would be most appreciated.
yes, it matters that you have only one instance of dataView. and also sooner or later you will come up to the fact that one variable for all grids is also a bad idea
so add a var dataView to your loop, it should solve the problem