Using jQuery to set the value of a hidden select list

Problem

A StackOverflow question was looking to automate a jQuery widget where a user visible text field and list element were used to set a hidden dropdown.

Interacting with the visible control can be complicated, so Abe’s answer suggested to use jQuery to make the select list visible and then interact with the select list with the normal Watir API.

For example, let us assume we have the following page, which has a hidden dropdown:

<html lang="en">
  <head>
    <script src="https://code.jquery.com/jquery-1.9.1.js"></script>
    <script src="https://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
  </head>
  <body>
    <select id="list" style="display:none">
      <option value="a" selected>Option A</option>
      <option value="b">Option B</option>
    </select>
  </body>
</html>

Note that while we can do some interaction with the select list, setting the options will raise an exception:

browser.select_list(:id => 'list').value
#=> "a"
browser.select_list(:id => 'list').select_value('b')
#=> Element is not currently visible and so may not be interacted with (Selenium::WebDriver::Error::ElementNotVisibleError)

Applying Abe’s solution to show the select list, the code would be:

attrib = 'id'
value = 'list'
browser.execute_script(%{jQuery("select[#{attrib}|='#{value}']").show();})
browser.select_list(:id => 'list').select_value('b')
browser.select_list.value
#=> "b"

To avoid having to define the locating of the select list twice (once in jQuery and once in Watir), we can refactor the jQuery to use the Watir located element:

select_element = browser.select_list(:id => 'list')
browser.execute_script("$(arguments[0]).show();", select_element)
select_element.select_value('b')
select_element.value
#=> "b"

Assuming that we are not trying to test the widget itself, forcing the select list to be visible seems like a good approach. However, if we are using jQuery to manipulate the select list visibility, why not just set the value of the hidden select list directly?

Solution

Using jQuery, we could directly set the hidden select list’s values with:

select_element = browser.select_list(:id => 'list')
value = 'b'
browser.execute_script("$(arguments[0]).val('#{value}');", select_element)
browser.select_list.value
#=> "b"

Alternatively, for more flexibility in determining which option to select (eg we want to select by text), we could locate the specific option element using Watir and then use jQuery to select that option:

select_element = browser.select_list(:id => 'list')
option_element = select_element.option(:text => 'Option B')
browser.execute_script("$(arguments[0]).prop('selected', true);", option_element)
browser.select_list.value
#=> "b"

Risks

One problem I found with using jQuery to set the select list was that events were not triggered.

For example, if the select list was was changed to have an onchange event:

<html lang="en">
  <head>
    <script src="https://code.jquery.com/jquery-1.9.1.js"></script>
    <script src="https://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
  </head>
  <body>
    <select id="list" style="display:none" onchange="javascript:alert('change');">
      <option value="a" selected>Option A</option>
      <option value="b">Option B</option>
    </select>
  </body>
</html>

Neither of the two jQuery approaches to directly set the list triggered the alert. From another StackOverflow question it turned out that you need to manually trigger the event. Therefore, you would need to change the executed scripts to:

browser.execute_script("$(arguments[0]).val('#{value}').change();", select_element)

or

browser.execute_script("$(arguments[0]).prop('selected', true).change();", option_element)

If there were other events that had to be triggered, presumably you would also have to manually trigger them too.

Conclusion

While selecting options directly is possible, it does not seem to provide any significant benefit.

Advertisements
This entry was posted in Watir, Watir-Webdriver and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s