Unable to check/uncheck specific checkbox based on text - ruby

I am trying to check and uncheck checkboxes based on following requirements:
If a particular text is present, I need to check the checkbox for it.
If some other text has checkbox set, I need to uncheck that checkbox
<table class="adm">
<tbody>
<tr class="action">
<td width="20px">
<input class="checkbox" type="checkbox" name="checkbox1">
</td>
<td>
<span class="label">
<script id="start"></script>
Action1
<script id="end"></script>
</span>
<p class="desc">
<script id="start"></script>
Description1
<script id="end"></script>
</p>
</td>
</tr>
</tbody>
</table>
<table class="adm">
<tbody>
<tr class="action">
<td width="20px">
<input class="checkbox" type="checkbox" name="checkbox2">
</td>
<td>
<span class="label">
<script id="start"></script>
Action2
<script id="end"></script>
</span>
<p class="desc">
<script id="start"></script>
Description2
<script id="end"></script>
</p>
</td>
</tr>
</tbody>
</table>
And there are 5 checkbox classes like the one above.
So , I need to check :
Find "Action1" -> check it's checkbox.
If "Action2" has checkbox set -> uncheck that checkbox.
So, need to set checkbox as per requirements and uncheck all other checkboxes.
I found this to check/uncheck all checkboxes:
checkbox_class = /checkbox/
#browser.checkboxes(:class => checkbox_class).each do |checkbox|
if(!checkbox.checked?)
p "checkbox not set"
checkbox.set
else
p "checkbox set"
checkbox.clear
end
end
But I am unable to cater this as per my requirements, tried this:
checkbox_class = /checkbox/
action_class = /label/
#browser.checkboxes(:class => checkbox_class).each do |checkbox|
if(!#browser.span(:class=>action_class,:text=>"some_action").checkbox.checked?)
p "checkbox not set"
checkbox.set
else
p "checkbox set"
checkbox.clear
end
end

The problem is that your loop and your conditional are out of sync.
#browser.span(:class=>action_class,:text=>"some_action").checkbox
is the same thing as:
#browser.span(:class=>action_class,:text=>"some_action").checkbox(:index => 0)
It refers to the same element on the page, regardless of the checkbox in your loop.
It might be easiest to uncheck all checkboxes with the code you found, then find checkbox with the action you want and just check that box.

Given that the labels and checkboxes are related by their shared ancestor, the table element, I think it is easier to iterate through the tables. Within each table, you can check the label text and then decided whether to set/clear the checkbox.
The following will set the "Action1" checkbox and uncheck the rest:
action = 'Action1'
browser.tables(:class => 'adm').each do |table|
# Check if the label matches the action we want to check
value = (table.span(:class => 'label').text == action)
# Set the checkbox if the label matches, otherwise clears
table.checkbox.set(value)
end

I think the following will work:
action_trs = #browser.trs(class: ‘action’)
action_trs.each do |action_tr|
if action_tr.td(index: 1).span.text == ‘some_action’
action_tr.checkbox.set unless action_tr.checkbox.set?
else
action_tr.checkbox.clear
end
end
Good luck! :)

Related

Why "checked" attribute doesn't apply to my Thymeleaf's checkboxes?

I was working with Spring and Thymeleaf when I've encountered the following problem: I need a Form object, which has a list of items (Item) as attribute; I'm using an html form to print the Name of the Item, and to generate a checkbox for each Item (any checkbox's value is the corresponding item's id).
The form works correctly, sending to the Controller a list of item's ids corresponding to the checked checkboxes.
However, now, I'm trying to check some checkbox upon the occurrence of a condition (if itemIds, which is a list, contains the current item's id). For that I'm using:
th:checked="${#lists.contains(itemIds, item.id)}"/>
But it doesn't work (checkbox are all unchecked).
I tried also with a "dummy test":
th:checked="${1 == 1 ? 'checked' : ''}"/>
But, again, all the checkbox remain unchecked; the "checked" attribute is ignored as you can see in this example of the rendered HTML:
<input type="checkbox" value="12" class="chkCheckBox" id="ids1" name="ids">
What am I doing wrong? What am I missing here?
form.html
<form th:action="#{${uriBase}+'/new/' + ${date}}"
method="POST" th:object="${form}">
<div class="table-responsive">
<table class="table">
<thead class=" text-primary">
<tr>
<th>Name</th>
<th><input type="checkbox" th:id="checkAll"/>Check</th>
</tr>
</thead>
<tbody>
<tr th:each="item : ${items}">
<td th:text="${item.name}"></td>
<td>
<input type="checkbox" th:field="*{ids}"
th:value="${item.id}" th:class="chkCheckBox"
th:checked="${#lists.contains(itemIds, item.id)}"/>
</td>
</tr>
</tbody>
</table>
<button type="submit" class="btn btn-primary pull-right">Submit</button>
<div class="clearfix"></div>
</div>
</form>
Form class
public class Form implements Serializable {
private List<Long> ids;
//getter and setter
}
Thank you in advance.
I have been struggling with this as well. If you use the th:field it will override the checked and value options, as Xaltotun mentions, because it is trying to get the value and checked option from the field/form.
If you change it to th:name it should work how you want...
But this forum seems to be helpful for doing it with th:feild.
As far as I understand there are 2 issues in your post:
The dummy example is incorrect.
th:checked="${1 == 1 ? 'checked' : ''}"
In fact the value must true or false not 'checked'. If you try with
th:checked="${1 == 1}"/>
It will work.
If you set th:field="*{ids}" then the checkbox should be trying to get the value from the field item.ids and will not use the "th:checked" or "th:value" properties. Does the item has the field ids?

2 forms - Credit Card and Checking Account - 2 identical xpaths for one checkbox - automation will not click the checkbox

here is the xpath I am using
//tr[#id = 'inputSavePaymentAccounts']/descendant::input[#type = 'checkbox' and #name = 'payAck' and #tabindex = '10'
here is how I can get it to check the checkbox
jQuery('.payAck').prop('checked', true)
here is the checking account html that is inside an iframe
<tr id="inputSavePaymentAccounts" class="savePaymentAccounts" style="display: table-row;">
<td class="addCCLabel" style="padding-top: 15px;">Save this Payment Method</td>
<td style="padding-top: 15px;">
<input class="payAck" type="checkbox" onchange="friendlyNameShow()" name="payAck" tabindex="10">
</td>
</tr>
here is the credit card html that is inside the same iframe
<tr id="inputSavePaymentAccounts" class="savePaymentAccounts" style="display: table-row;">
<td class="addCCLabel" style="padding-top: 15px;">Save this Payment Method</td>
<td style="padding-top: 15px;">
<input class="payAck" type="checkbox" onchange="friendlyNameShow()" name="payAck" tabindex="25">
</td>
</tr>
The main issue is that when i use:
jQuery('.payAck').prop('checked', true)
it checkmarks the checkbox however, at the time the checkbox is checked I am suppose to see a text box display, which is not happening with the above jquery. I was hoping the execution of xpath would solve this
see these for a more clearer picture
image of checkbox http://prnt.sc/c12b1p
image of checkbox when it is checked with text box displaying (need this to happen) http://prnt.sc/c12b7q
First of all, I would recommend you remove the inline javascript. Your primary selector in this case is a class and the class is assigned to 2 elements (at least from what I see in your example). When you check the checkbox using jQuery with the class selector, it is going to trigger all the elements that belong to that class and I don't think that is what you intend to do. Also, using click() will work, but that will cause friendlyNameShow() to be called twice and you will need to check the state of the checkbox since you are not explicitly checking/un-checking it. Try using and Id instead.

Angular 2 doesn't update my view after I add or edit item

I've finally made my app in angular 2. Everything is solved, except one thing. When I add item into my table or edited it, I can't see the change until I refresh page or click for example next page button (I have implemented pagination). I included:
<script src="node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
in this order. My method for adding item is very simple:
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();}
Whhen I add item, and put breakpoint on get method, It is called correctly and I get right information from my DB, but I don't know why view isn't refreshed then. Do you have any idea why is it happened? Thanks for suggestions!
EDIT: department is just department: Department, where Department is interface with properties (departmentNo, departmentName, departmentLocation). The view for adding item looks like:
<form [ngFormModel]="myForm"
(ngSubmit)="addDepartment(newItem); showAddView=false" [hidden]="!showAddView" align="center">
<div>
<label for="editAbrv">Department name:</label><br>
<input type="text" [(ngModel)]="newItem.departmentName" [ngFormControl]="myForm.controls['departmentName']" >
<div *ngIf="myForm.controls['departmentName'].hasError('required')" class="ui error message"><b style="color:red;">Name is required</b></div>
</div>
<br/>
<div>
<label for="editAbrv">Department Location:</label><br>
<input type="text" [(ngModel)]="newItem.departmentLocation" [ngFormControl]="myForm.controls['departmentLocation']" >
<div *ngIf="myForm.controls['departmentLocation'].hasError('required')" class="ui error message"><b style="color:red;">Location is required</b></div>
</div>
<br/>
<div>
<button type="submit" [disabled]="!myForm.valid" class="ui button">Add item</button>
<button><a href="javascript:void(0);" (click)="showHide($event)" >
Cancel
</a></button>
</div>
</form>
and my department table is:
<table align="center">
<thead>
<tr>
<td>#</td>
<td><strong>Department</strong></td>
<td><strong>Department Location</strong></td>
<td><strong>Edit</strong></td>
<td><strong>Delete</strong></td>
</tr>
</thead>
<tbody>
<tr *ngFor="#department of departments | searchString:filter.value ; #i = index">
<td>{{i + 1}}.</td>
<td> {{department.departmentName}}</td>
<td>{{department.departmentLocation}}</td>
<td>
<button class="btnEdit" (click)="showEdit(department)">Edit</button>
</td>
<td>
<button class="btnDelete" (click)="deleteDepartment(department)" >Delete</button>
</td>
</tr>
</tbody>
</table>
With this code, you don't wait for the response of the addDepartment request and execute the getAll request directly.
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();
}
You should move the call to getAll within the callback registered in subscribe. At this moment, the addDepartment is actually done and you can reload the list...
The code could be refactored like this (it's a guess since I haven't the content of addDepartment and getAll methods):
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(addedDepartment => {
this.department = this.getAll();
});
}
This issue occurs because of the way you're using departmant and how change detection works. When you use *ngFor="#department of departments", angular change detection looks for a object reference on departments array. When you update/change one of the items in this array object reference to the array itself doesn't change, so angular doesn't run change detection.
You have few options:
1) change reference of the array by replacing it with new array with updated values
2) tell angular explicitly to run change detection (which I think is easier in your case):
constructor(private _cdRef: ChangeDetectorRef) {...}
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();
this._cdRef.markForCheck();
}

How to click on the table cell for particular text

The following is the DOM details:
<div id: "abc_440"
<table class = "listtable" >
<tbody>
<tr>
<td id = "someid" >
<td class = 'someclass_item"> This is Text </td>
<td class = 'someclass_button">
< a > Add </a>
</td>
</tr>
</tbody>
</table>
</div>
I need to click on 'Add' for particular text at "This is Text". I have to use div with ID (abc_440)to locate the corresponding table as there are may divs with this same dom layout. but index at div ID (for example 440) keeps changing to random number. How do I handle it in general ?
Please help.
I think that what you want to do is very similar to the previous Watir question.
Given that the id is randomly generated, it does not sounds like a good way of finding the link. You will likely need to use the text of the same row.
Assuming that the "This is Text" is unique (as you said you want to find the Add link for it), you can find that td, go to the parent row and then get the link.
b.td(:text => 'This is Text').parent.link.click
If you need to ensure that the text is in the second column, then you can do:
b.trs.find{ |tr|
tr.td.exists? and tr.td(:index => 1).text == 'This is Text'
}.link.click
The tr.td.exists? is added in case some of your rows do not have any tds (example a header row), which would cause an exception when checking the second criteria.
Don't mix quotes in HTML tags. id: doesn't work. <td>s should rarely be empty. The Add button should be a button, not an <a>nchor element. Buttons only work in <form>s.
<form id="abc_440" action='someURI'> <!-- The handler for the button. -->
<table class="listtable">
<tbody>
<tr>
<td id = "someid">
<!-- What goes here? -->
</td>
<td class='someclass_item'>
This is Text
</td>
<td class='someclass_button'>
<button name='add'>Add</button>
</td>
</tr>
</tbody>
</table>
</form>
You should be able to find the button through its name attribute, add, and through the form's id attribute, abc_440. Who generates the ids?
Once you have the problem of finding the add button solved, and figuring out where the form's id comes from, please then stop using tables for formatting. There's no need for that. Learn about <form>s, <fieldset>s, <legend>s, and <label>s. I doubt you need the *some_id* part, the text part should probably be a <label>, and you can use CSS to format your <label>s as:
label {
width: 150px;
float: left;
}
fieldset p {
clear: left;
}

Using Ruby Watir, how can I select a checkbox that has a changing ID?

This is the HTML I'm working with:
<div class="pbSubsection">
<table class="detailList" cellspacing="0" cellpadding="0" border="0">
<tbody>
<tr>
<td class="labelCol">
<label for="00Ni0000003bw8O">Becomes Asset</label>
</td>
<td class="dataCol col02">
<input id="00Ni0000003bw8O" type="checkbox" value="1" tabindex="8" name="00Ni0000003bw8O" checked="checked">
</td>
I need to select the checkbox.
I cannot use the ID because I'm doing this across multiple orgs, and the ID is different in every org. Is there a way I can select by the label text or by the tabindex?
It is probably safer to get the checkbox by the label text rather than the tabindex.
Solution 1 - :label locator:
If you are using watir-webdriver, it possible to locate an element directly based on its label text - via the :label locator. You can do the following:
#Exact match of label text:
b.checkbox(:label => 'Becomes Asset').set
#Partial match of label text using regex:
b.checkbox(:label => /Asset/).set
Note that this assumes that the 'for' attribute of the label matches the 'id' attribute of the input element.
Solution 2 - Matching label to input:
For a solution that works in watir-classic (as well as watir-webdriver), you can:
Get the label element by text
Get the for attribute of the label element
Get the associated checkbox by its id, which matches the label element's for attribute
The following will work for your page to clear the checkbox:
label = browser.label(:text => 'Becomes Asset')
browser.checkbox(:id => label.for).set
To select the checkbox based on the tabindex, using a :css or :xpath locater should do the trick:
b.checkbox(:xpath => "//input[#tabindex='8']").set
b.checkbox(:css => 'input[tabindex="8"]').set

Resources