Web2py URL callback hidden when clicked and loading ajax - ajax

I have been developing an application using web2py. I have a page with a callback link which sends information to another function, this loads the results via ajax in the right sidebar of the page. When the link is clicked, the link itself disappears but the results are loaded correctly. I have to refresh the page for the links to come back. I have been looking at this for ages but can't figure it out, I am relatively new to web2py so probably missed something obvious.
Here is some code:
The view (With the link):
{{if hosts == "Please select a category":}}
{{response.write("Please select a category")}}
{{else:}}
<ol>
{{for i in hosts:}}
<li>{{=A(i['HostName'], callback=URL('selection','getResults.load', vars=dict(clicked=i['HostName'])), target="monitoredDevice")}}</li>
{{pass}}
</ol>
{{pass}}
{{end}}
{{block right_sidebar}}
<div id="monitoredDevice">
</div>
{{end}}
The controller action:
def getResults():
hostName = request.vars.clicked
# hostName = request.vars.hostNameSelected
print(hostName)
try:
task_status = scheduler.task_status(db.scheduler_task.task_name==hostName, output=True)
result = task_status.result
# create_compare_graph()
except(AttributeError): # Error is because there is no scheduler and therefore no status, need to set the values to 0
result = emptyTaskStatusResultsToZero()
try:
return dict(result)
except(TypeError): # There is a task scheduled however there is no run data as it has not been run before. Causes an error.
return emptyTaskStatusResultsToZero()
I think there is something wrong with the =A link in the view?
Thank you!

The method just prevents the view from getting an error if nothing is returned so I set all the values to zero so the view has something to render.
def emptyTaskStatusResultsToZero():
return {'percent_diff_in': 0, 'percent_diff_out':0, 'now_avg_30mins_in': 0
, 'now_avg_30mins_out':0, 'prev_week_avg_30mins_in':0, 'prev_week_avg_30mins_out':0,
'percent_more':0,'percent_less':0, 'count':0}

Related

Capybara - Finding a disabled button located in table row

I have a button
<button type="button" id="saveListing" class="button small save-button" data-bind="enable: saveEnabled, click: save"><i class="fa fa-save"></i> Save</button>
located in the tr of a table.
I wrote a function for testing the button status, simply using:
And(/^...the button "(.*?)" on "(.*?)" page is disabled$/) do |button_name, page|
button_id = ConfigHelper.get_button_info(button_name, page)['id']
button_class = ConfigHelper.get_button_info(button_name, page)['class']
if !button_id.nil?
find_button(button_id)[:disabled].should eq 'true'
elsif !button_class.nil?
find(button_class)[:disabled].should eq 'true'
else
button_text = ConfigHelper.get_button_info(button_name, page)['text']
find('button', text: button_text)[:disabled].should eq "true"
end
end
However, this block does not work for a button in a table row. I also tried add checking by button id, and it also did not work. How can I implement it without taking table id as a parameter? (As I don't want to write table id inside the feature)
When using id, the error is:
Capybara::ElementNotFound: Unable to find css ".saveListing"
or using text:
Ambiguous match, found 4 elements matching css "button" (Capybara::Ambiguous)
Thanks.
Capybaras find_button doesn't search css classes at all so unless you have overwritten find_button I'm not sure why you would be getting that error from using it with an id. find_button will search by the id, value, text content, or title attribute of the button, and also supports a disabled filter for searching. More stable (if the status of the button is changing due to JS) versions of those checks would be
find_button('saveListing', disabled: true).should be #Note: no # in front of the id here since its not a css selector
find_button('button text', disabled: true).should be
These would be more stable because they will utilize Capybaras waiting behavior to find the disabled button, whereas the way they were written previously would immediately find the button and error if they weren't yet disabled.
saveListing is the id of your button, not a class. In css selectors, dot is used for classes and hash sign is used for ids.
Therefore, you should either be using #saveListing or .save-button, but not .saveListing. This is why your first matching fails.
As to why the second one does - I guess there are 4 rows, each with one button and Capybara doesn't know which one you are referring to. If you want to check this condition for all of them, you could use all instead of find like this:
all('button', text: button_text).each do |button|
button[:disabled].should eq "true"
end

Interact with a file_field inside span - Watir/Selenium-Webdriver

How do I interact with a file_field thats hidden by its parent?
<span class="btn button-large fileinput-button">
Select files...
<input accept="image/png, image/gif, image/jpeg" id="gallery_files" multiple="multiple" name="gallery_files" type="file">
</span>
The button overlays the input, therefore it's not visible.
Edit
For the record, here's my code:
data[:photos].each do |photo|
$browser.file_field.set photo
end
and the error: Watir::Wait::TimeoutError: timed out after 20 seconds, waiting for {:tag_name=>"input", :type=>"file"} to become present
Workable example in a Gist
I was a bit suprised, but I was able to set the file field in the sample HTML without any issue using:
browser.file_field.set('path/to/file.txt')
From the code, it looks like setting the file field only requires the input to exist. It does not require it to be visible (or present).
Given that you are getting a Watir::Wait::TimeoutError exception, I would guess that your code is actually failing before the file_field.set. As it looks like the page has the input in a dialog, I am guessing your code actually looks more like:
$browser.file_field.wait_until_present
data[:photos].each do |photo|
$browser.file_field.set photo
end
It would be the wait_until_present method that is actually throwing the exception.
Solution 1
Assuming that an explicit wait method is being called for the file field, you should be able to just remove the wait.
If you have the wait because the dialog is being loaded by Ajax, you could try waiting for a different element instead - eg the parent span.
Solution 2
If for some reason you need the file field to be present, you will need to change its CSS. In this case, the opacity:
p $browser.file_field.present?
#=> false
$browser.execute_script('arguments[0].style.opacity = "1.0";', browser.file_field)
p $browser.file_field.present?
#=> true
For my situation, this worked:
$browser.execute_script("jQuery(function($) {
$('.fileinput-button').css('visibility', 'hidden')
$('#gallery_files').css('visibility', 'visible').css('opacity', '1').css('width', '100').css('height', '50')
})")
I had to hide the parent span, then show, resize, and change the opacity of the input

Watir. Select multiple radio button options

The issue I'm dealing with, and unable to solve due to my ignorance, is that I have a page on a browser with different education requirements which each have four radio buttons. I want to be able to select a certain radio button for each education requirement.
The code I have is like this:
radios = browser.radios
radios.each do |radio|
radio.input(:value => "very").set
end
However this keep giving me an error message saying: "undefined method 'set' for #Watir::Input:0x103a5d508"
I did something similar for select_lists where I changed the option of all select_lists on a page to the 2nd option which worked:
lists = browser.select_lists
lists.each do |list|
list.option(:index, 1).select
end
For my code for the radio buttons I tried using radio.option but it gave me a similar error: "NoMethodError: undefined method `set' for #Watir::Option:0x103a466a0"
Problem
The code
radios = browser.radios
radios.each do |radio|
radio.input(:value => "very").set
end
Says that for each radio button on the page, set the first input element with value "very". This suggests that you are looking for html like:
<radio>
<input value="very" />
</radio>
This is probably not what the html looks like.
Solution
I assume the html you really want to set is like:
<input type="radio" value="very" />
To set each radio button with value "very", the code should be:
# Get a collection of all radios with value "very"
radios = browser.radios(:value => "very")
# Iterate through each radio button in the collection and set it
radios.each do |radio|
radio.set
end
This can be shortened to simply:
browser.radios(:value => "very").each(&:set)

Datamapper breaks app when saving urls

I'm making a URL shortener application in Sinatra. It works as follows:
The front page is a form with one field, to enter a long url into:
<form action="" method="post">
<input type='url' name='url' placeholder='Enter URL to be shortened'>
<input type="submit">
</form>
The form posts to the same front page and the code for posting to '/' is this:
post '/' do
#Makes variable of POSTed url.
#long = params[:url]
loop do
#makes random six letter hash
#rand = (0...6).map{(65+rand(26)).chr}.join.downcase
#don't generate another one if it isn't found in the database
break if Short.first(id: "#{#rand}").nil?
end
#saves url and hash to database
#input = Short.create(url: #long, id: #rand)
#displays link with hash to be copied into browser address bar
"http://192.168.1.3:999/"+#rand
end
The problem is that when I submit the form, it doesn't return the http://192.168.1.3:999/... or anything I put after the #input=Short.create(... line. It doesn't return any errors, even when raise_on_save_failure is true. If I comment that line out, it works fine (except when trying to use the shortened url).
EDIT: When I change the code to allow non-urls, it functions perfectly normally. It only breaks with the exact url format.

JSP: Function call inside loop becomes very slow. Help me optimize

In my JSP, I loop through an object containing a list of employees and display it.
For each employee row, I also provide a link so that the user can view the employee's details. The link calls a Javascript function where the employee ID is passed.
The problem I am having is that the response time dramatically increases with the number of rows in my object. When my object contains over a thousand records, it takes at least 30 secs to render the page. Here's the code:
function getDetail(empID){
//AJAX call to get employee details}
}
.
.
<table>
<c_rt:forEach var="emp" items="${employeeListObj}">
<tr>
<td>
<c:out value="${emp.lastName}" />
</td>
</tr>
</c_rt:forEach>
</table>
I have narrowed down the culprit to the employee ID parameter being dynamic or being evaluated at runtime. I intially thought is it was a JSTL c:out issue, but I also tried changing to an ordinary JSP variable (i.e. getDetail('<%=ctr%>'), and the response time is still slow.
But when I changed it to a static string (i.e. getDetail('some static string')), the response time becomes fine.
I also tried passing it as a function (i.e. onClick="getDetail(function () {return ''})") but response time still didn't improve.
Is there a better (more optimized) way of doing this that will result in a better response time?
Thanks for the replies but I have figured out a simple solution. Not the most elegant, but it's a simple change and it serves my end user's needs (they dont want pagination, just a scrollable DIV area).
Instead of using this statement inside the loop:
<a href="#" onClick="getData('<c:out value="${emp.id}"/>')">
I used the employee ID as the ID of the anchor tag and passed that one instead:
<a id='<c:out value="${emp.id}"/>' href="#" onClick="getData(this.id)">
I don't know why, but the difference was night and day in terms of page rendering time. It now renders for just less than 5 secs compared to over a minute when passing the c:out value directly. I was dealing with 10,000 records btw.
If the problem is in the browser, you could replace the click handlers with attributes containing the number and a single click handler added through Javascript (eg, jQuery)
EDIT: For example:
$('table.SomeClass a').click(function() {
getDetail($(this).attr('data-employeeId'));
return false;
});

Resources