Cypress - Click checkbox that depends on the value of another checkbox on a table - reactjs

I have a table with 2 columns of checkboxes.
I want to click the first checkbox that has the checked value on the right.
Note: All the checkboxes on the left are not disabled and all the checkboxes on the right are disabled.
Edit:
My DOM looks like this:
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{items.map(item) => (
<tr>
<td>
<input type="checkbox" />
</td>
<td>
<input type="checkbox" checked={item.posted} disabled />
</td>
</tr>
)
}
</tbody>
</table>
It is reiterated by the data from the api thats why the checked state of the checkbox is dynamic

Try finding the first checked, then the move to the first checkbox
cy.get('input:checked') // all checked inputs
.eq(0) // first one
.parent('td') // move to cell
.prev() // previous cell
.find('input') // it's input
.click()
To clarify how to correctly use .each(), you need to use the 3rd parameter collection and also return false to avoid checking every row which is checked on the right.
cy.get('input[type="checkbox"]')
.each(($ele, index, collection) => {
if ($ele.is(':checked')) {
cy.wrap(collection).eq(index-1).click()
return false; // break early to only click the first
}
})

You try something like this, iterate over all the checkboxes, once you find the checkbox that is disabled, you can go to a the previous checkbox using .eq(index-1) and then perform the click().
cy.get('input[type="checkbox"]').each(($ele, index) => {
if ($ele.is(":disabled")) {
cy.wrap($ele).eq(index-1).click()
}
})

Related

Laravel: Generated buttons with loop (How to tell which one is click)

Hello Again Stockoverflow,
Hope all is well with you,
Can you help me again with Laravel/Ajax?
From the given code below I generated the table shown on the picture,
what I want to accomplish is to save each row when a button is click,
I know enough ajax to do the saving, the problem is how can I tell ajax and jquery which row button is click and which text input has the value since, the text inputs and buttons are generated with loop/array?
Thanks.
if($list_factors)
{
foreach ($list_factors as $key => $list_factor) {
// dd($list_factors);
$output.='<tr>'.
'<td>'.$list_factor->id.'</td>'.
'<td>'.$list_factor->factor_description.'</td>'.
'<td><input type="text" id="score" /></td>'.
'<td><button class="btn btn-info" id="submitScore">OK</button></td>'.
'</tr>';
}
return Response($output);
}
First of all, you can't use id="submitScore" attribute in the button generated within the loop because id must be unique. Instead you can use class="submitScore". Also, you can't use id="score" in the input, use class="score" Since you are going to use jQuery then you may try something like this:
// Register the event handler on 'submitScore' class of button
$('button.submitScore').on("click", function(e) {
var row = $(this).closest('tr');
var inputValue = row.find('.score').val();
console.log(inputValue);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<td><input class='score' /></td>
<td><button class='submitScore'>OK</button></td>
</tr>
<tr>
<td><input class='score' /></td>
<td><button class='submitScore'>OK</button></td>
</tr>
</table>

React maintain focus position after clicking on different element

I have a two column table. The right column has input fields. When an input field is focused (as shown in picture below), it displays a non focusable button on the right side of the table. When the user clicks this button, it should modify the focused input field with it's text but reversed. This button is non TABable.
My problem is that when the user clicks the button to reverse the text, it unfocuses his current position in the table. Meaning, when he clicks tab again after clicking the button, the focus goes back to the top of the page instead of continuing from the input box that just got reversed.
How can I retain the tab position even when the user clicks on other non TABable elements?
Your best tactic is to keep track of what element is currently focused on in a global state variable. When each element is focused on, whether through clicking on it or tabbing onto it, you have to detect the change in focus and update the state variable which is keeping track of that. That means that each of your table cells that is tabable needs an eventListener for onFocus that updates the state variable. Then you can attach an event listener to your button which will shift the focus to the adjascent cell. So if your table looks like this:
<table>
<tr>
<td class="title">Source</td>
<td class="title">Note</td>
</tr>
<tr>
<td id="1" tabindex="1">Climbing</td>
<td id="2" tabindex="2">I really like this sport</td>
</tr>
<tr>
<td id="3" tabindex="3">Running</td>
<td id="4" tabindex="4">Meh not a fan</td>
</tr>
<tr>
<td id="5" tabindex="5">Biking</td>
<td id="6" tabindex="6">I need a bike</td>
</tr>
<tr>
<td id="7" tabindex="7">Eating</td>
<td id="8" tabindex="8">who isnt a fan</td>
</tr>
</table>
<button id="toggleButton">Toggle focus</toggle>
You can set up some basic JS like so:
// global state variable
let currentlyFocusedElement;
const tds = document.querySelectorAll('td')
// attach onFocus events to all your tabable boxes
tds.forEach( td => {
td.addEventListener('focus', () => {
currentlyFocusedElement = td
console.log(currentlyFocusedElement)
})
})
const toggleButton = document.querySelector('#toggleButton')
// use the button to change the focus programmatically
// my if statements here are a little slapdash, but they work to solve your problem, can be easily adjusted
toggleButton.addEventListener('click', () => {
const number = currentlyFocusedElement.id
console.log(number)
if (number % 2 === 0){
document.getElementById(`${number-1}`).focus()
} else if (number % 2 === 1) {
document.getElementById(Number(number)+1).focus()
}
})
I made a working example here: codepen tab thing
Of course after writing this all up I saw that your question has a reactjs tag and it makes me wish you would have been way more specific in your question and even included your code. I'm sure you can adapt some of my vanilla js solution to a react environment.

uib-pagination not paging correctly when new line is added

I have a table of people showing and if there are more than 3 then the pagination controls should show. I want to allow the user to add/delete people to/from that table.
I have been able to add and delete from the table, and if there are 3 or less people, they display correctly. If I add a fourth person, I would expect the pagination control to go to the 2nd page and the top row. What appears to happen though is the pagination control, will show a '2' for a possible page number, but the 4th person shows on the first page....all others added also go to the first page. It seems as though the page numbers at the bottom do not work - the page doesn't change. I do update the current page value, but it doesn't seem like it is being reflected.
Below is a portion of my View. There are some extra pieces in it that don't really relate to paging. I use them to get to the right line to provide the user an input field to enter an employee name if the Add Lead button was clicked. Once they find who they are looking for, then the values are just displayed.
<table class="table" >
<tbody ng-repeat="boLead in components[selectedRow].boleads " pagination-id="boleads" >
<tr >
<td id="leadId" >{{boLead.boLeadId}}</td>
<td ng-show="(inserted == boLead && newLead) ">
<input type="text" class="form-control" ng-model="boLead.boLead" ng-model-options='{ debounce: 800 }' ng-change="searchEmployee(boLead.boLead)" />
<table class="table table-hover table-bordered" ng-show="employees.length">
<tr>
<th>Employee ID</th>
<th>Employee Name</th>
</tr>
<tr ng-repeat="result in employees" ng-click="pickEmployee(result, boLead)">
<td>{{result.user_id}}</td>
<td>{{result.name}}</td>
</tr>
</table>
</td>
<td ng-show="(inserted != boLead && !editq || (editq && editl != ($index+(3*(pagination.current-1)))) )">{{boLead.boLead}}</td>
<td ng-if="mode == 'edit'">
<select class="form-control input-md" ng-model="boLead.forwardONS" >
<option>Yes</option>
<option>No</option>
</select>
</td>
<td ng-if="mode == 'edit' && (!checkNewLead(boLead) && !editq)">
<button type="button" ng-click="removeLead($index+(3*(pagination.current-1)))" class="btn btn-danger fa fa-trash"> Delete</button>
</td>
<td ng-if="mode == 'view'" ng-bind-html="boLead.forwardONS"></td>
</tr>
</tbody>
</table>
<uib-pagination previous-text="‹" next-text="›" ng-model="pagination.current" class="pagination-sm" ng-if="pagination.totalLeads > 3" items-per-page="3" total-items="pagination.totalLeads" boundary-link-numbers="true"></uib-pagination>
Controller:
This is the portion for adding a person to the list
$scope.addLead = function() {
$scope.inserted = {
prgGuid: $scope.components[$scope.selectedRow].prgGuid,
componentId: $scope.components[$scope.selectedRow].componentId,
boLeadId: '',
boLead : '',
forwardONS: ''
};
if (typeof $scope.components[$scope.selectedRow].boleads == 'undefined') {
$scope.components[$scope.selectedRow].boleads = new Array($scope.inserted);
} else {
$scope.components[$scope.selectedRow].boleads.push($scope.inserted);
}
$scope.newLead = true;
$scope.editq = true;
$scope.editl = $scope.components[$scope.selectedRow].boleads.length-1;
if ($scope.components[$scope.selectedRow].boleads.length > 3) {
var pg = Math.ceil($scope.components[$scope.selectedRow].boleads.length / 3);
$scope.pagination.current = pg;
}
$scope.pagination.totalLeads = $scope.components[$scope.selectedRow].boleads.length;
};
When I step through this, the $scope.pagination.current = pg; does update properly with what the current page should be. For instance, once a 4th person is added, it becomes 2. This is the ng-model in the pagination controls, but it just doesn't seem like the pagination is listening, since the screen doesn't change to show the new line but instead all four show.
I've looked at a lot of posts, but I seem to be doing something different than everyone - I couldn't find an example of someone adding a line and then the screen page when enough entries would require going to a new page.
I seem to have been able to fix my problem after looking at more examples...I added a slice to the table and it seems to work exactly how I wanted...
I changed this line:
<tbody ng-repeat="boLead in components[selectedRow].boleads " pagination-id="boleads" >
to:
<tbody ng-repeat="boLead in components[selectedRow].boleads.slice(((pagination.current-1)*3), ((pagination.current)*3)) " pagination-id="boleads" >

Expand/collapse odd row in AngularJs

I want to expand/collapse a row, I want to hide all odd rows and on clicking '+' button those hidden row should get visible, my current code is allowing me hide all the odd rows but on clicking '+' button all row are getting visible, my use case is to show only the odd row which is next to clicked even row.
<table class="table table-bordered">
<thead>
<tr>
<th></th>
<th>Name</th>
<th>Type</th>
</tr>
</thead>
<tbody ng-repeat="test in ctrl.SearchResults">
<tr ng-if="$even">
<td>
<button ng-click="ctrl.expanded = !ctrl.expanded" expand>
<span ng-bind="ctrl.expanded ? '-' : '+'"></span>
</button></td>
<td>{{test.apName}}</td>
<td>{{test.type}}</td>
</tr>
<tr ng-show="ctrl.expanded" ng-if="$odd">
<td></td>
<td>{{test.apName}}</td>
<td>{{test.type}}</td>
</tr>
</tbody>
</table>
The reason all the rows expand when you hit the plus, is that the variable expanded is on the controller. So all the rows are 'listening' to the same variable.
As atfornes pointed out in his answer, you could use the $index to identify each row. Another solution is to keep track of the current index on the controller and check for per row if he must be showed:
<tr ng-show="ctrl.expanded == $index" ng-if="$odd">
And on the click event of the plus sign you could have
ctrl.expanded = $index
Or you could handle this in the controller. In this case you can create a method on the controller which accepts the index and then set this index value to the controller's variable expanded.
At the button ng-click code, you could store the current $index with a code like:
<button ng-click="ctrl.expanded = !ctrl.expanded; ctrl.index = $index" expand>
then, you can change the ng-show condition to only display the item if ctrl.expanded and $index === ctrl.index + 1:
<tr ng-show="ctrl.expanded && $index === ctrl.index +1" ng-if="$odd">

Hide table rows in angular Js

I have a table, I am already given it CSS using ng-class if they satisfy a condition. Now I want to show only those rows who satisfy the same condition on a button click. I have wrote a controller which checks if the data received is within 24 hours are not and marks the data cell. Until this it's working.Now I need to add a button and show only the row which has this td marked as not received in time.
<tbody>
<tr ng-repeat ="data in log">
<td>{{data.UniqueId}}</td>
<td>{{data.Name}}</td>
<td ng-class ="{'data-notreceived' : dataNotReceived('data.receivedTime')}">{{data.receivedTime
}}
</tbody>
</table>
I think something like this should work. Basically, clicking the button will toggle between showing all or only the items marked as 'data not received'.
<tbody>
<tr ng-repeat ="data in log" ng-show="showAll || dataNotReceived(data.receivedTime)">
<td>{{data.UniqueId}}</td>
<td>{{data.Name}}</td>
<td ng-class ="{'data-notreceived' : dataNotReceived('data.receivedTime')}">{{data.receivedTime}}
</tr>
</tbody>
// in controller
$scope.showAll = true;
$scope.onButtonClick = function() {
$scope.showAll = !$scope.showAll;
return false;
}
From the information provided in question what I can say is: Use ng-show to show rows based on your condition.
<tr ng-show ="your_condition">
You could also use an ng-if rather than ng-show. See the differences here.
Really depends on how often the hide/show toggle needs to happen.
<tbody>
<tr ng-repeat="data in log" ng-if="showLast24Hrs(data.ReceivedTime)">
<td>{{data.UniqueId}}</td>
<td>{{data.Name}}</td>
<td>{{data.ReceivedTime}}</td>
</tbody>
and then in the controller,
$scope.showLast24Hrs = function(receivedTime){
if($scope.isLast24Hours) {
return receivedTime < 200; // Write your less than 24 hours check here
}
return true;
}
I wrote this demo on Codepen. Hope that helps.

Resources