How to target select dom element in Jest / RTL with attribute name - javascript

I am trying to target a select options DOM element for my test, currently the element is as follows:
<select name='element'>
<option value='1'>First element</option>
<option value='2'>Second element</option>
<option value='3'>Third element</option>
</select>
How would I target this element, as it does not have a class or text to reference it, I did have a look at https://testing-library.com/docs/queries/byrole, but I am a little confused as to which role it would be?
I have tried:
const selectElement = await screen.findByRole('select', {name: 'element'});
But this does not work? and any idea's on testing the change value would be good?

If you want to target the <select> element you need to use combobox as the role:
const select = screen.getByRole('combobox');
If you want to target a specific option you need to use the option role along with a its name:
const option2 = screen.getByRole('option', { name: 'Second element'});
You can also get all the option by doing getAllByRole:
const options = screen.getAllByRole('option');

Related

Javascript get value from select option based on label

Using either jQuery or pure JavaScript, how can I get the ID for a select option based on the label? So for example, given the following:
<select id="blah">
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
If I have the label "Two" but I need to know the value associated with it, how can I get that value from this select? I don't want to simply select it, I need to know what the value is.
If the only reference you have is really the actual text content, then you'll have to loop through the elements and check the content of each one. Shown here with jQuery just because it's less to type:
var result;
$("option").each(function() {
if ($(this).text() == "Two") {
result = $(this).attr("value");
return false;
});
});
Another option:
$('#blah').find('option:contains("Two")').val();
(Pun intended?)
Get all the options and then use find to get the one with specific text.
const optionEls = Array.from(document.querySelectorAll("#blah option"));
const hasText = text => el => el.textContent === text;
const optionWithTwo = optionEls.find(hasText("Two"));
console.log(optionWithTwo.value);
<select id=blah>
<option value=1>One</option>
<option value=2>Two</option>
<option value=3>Three</option>
</select>

display a part of value in select option

I have a select drop-down with country and code. In drop-down option, for user experience and understanding i am displaying name of the country along with country code.
As a normal functionality when a user selects any value from the drop-down that value gets displayed inside the input like this
however i want that only the country code should get displayed like this
Part of my code
<select name="countrycode" class="form-control pf-country" id="countrycode">
<option data-countryCode="IN" value="91">Code</option>
<option data-countryCode="IN" value="91">India (+91)</option>
<option data-countryCode="US" value="1">USA (+1)</option>
<optgroup label="Other countries">
<option data-countryCode="DZ" value="213">Algeria (+213)</option>
<option data-countryCode="AD" value="376">Andorra (+376)</option>
</optgroup>
</select>
The entire code is available here
Can anyone please suggest how to do it.
As per my understanding, You can try this one. As this example providing exact output as you mentioned in your questions.
https://silviomoreto.github.io/bootstrap-select/examples/#selected-text
Basically we're trying to change innerText of selected-option. It can be achieved easily by adding onchange event listener to the select tag.
But there's a little problem, on changing innerText we lose previous value of innerText, solution by #KKK solves problem but leaves this little thing.
Following code handles problem in complete ways. We're adding data-innerText atribute with previous value of innerText and also id="previous" to identify it. Please check this demo.
function simpleTweak(select){
var previouslySelectedTag = document.getElementById('previous');
if(previouslySelectedTag!=undefined){
previouslySelectedTag.innerText = previouslySelectedTag.getAttribute('data-innerText');
previouslySelectedTag.setAttribute('id','');
}
var innerText = select.options[select.selectedIndex].innerText;
select.options[select.selectedIndex].setAttribute('data-innerText',innerText);
select.options[select.selectedIndex].setAttribute('id','previous');
var value="(+"+select.options[select.selectedIndex].value+")";
select.options[select.selectedIndex].innerText = value;
}
As I understood, you need to change the display text after selecting the option, is it? If so, you can do it like this.
You can set the selected index's text in onchange event. But it will reset the text in the option when you click the dropdown again. You may need to change it back if you prefer.
function displayCountryCode() {
var countrycode = document.getElementById("countrycode");
countrycode.options[countrycode.selectedIndex].text = '+' + countrycode.value;
}
<select name="countrycode" class="form-control pf-country" id="countrycode" onchange="displayCountryCode()">
<option data-countryCode="IN" value="91">Code</option>
<option data-countryCode="IN" value="91">India (+91)</option>
<option data-countryCode="US" value="1">USA (+1)</option>
<optgroup label="Other countries">
<option data-countryCode="DZ" value="213">Algeria (+213)</option>
<option data-countryCode="AD" value="376">Andorra (+376)</option>
</optgroup>
</select>
The following JavaScript code will change the text of the selected option when you select it and change it back when you select a different one.
It does this by saving the values of the country name and country number as HTML5 data attributes (option.dataset.countryName & option.dataset.countryNumber)
Doing it this way, you don't have to change the format of the HTML from what you provided in your post.
I used vanilla JavaScript, so it'll work with or without jQuery.
window.addEventListener('load', () => {
let select = document.getElementsByName('countrycode')[0]
let options = document.getElementsByTagName('option')
for (let i = 1; i < options.length; i++) {
let option = options[i]
let matches = option.innerText.match(/(.*?) (\(\+\d+\))/)
option.dataset.countryName = matches[1]
option.dataset.countryNumber = matches[2]
// Set the value in the collection again now that the object has been changed
options[i] = option
}
select.addEventListener('change', () => {
for (let i = 1; i < options.length; i++) {
let option = options[i];
option.innerText = option.dataset.countryName + ' '
option.innerText += option.dataset.countryNumber
}
let option = document.querySelector('option:checked')
if (option !== options[0]) {
option.innerText = option.dataset.countryNumber
}
})
})
There's also a demo at CodePen

When registering both onchange and onclick on a select, the click event is triggered twice

Goal: Have a select whose option have nested structure when user clicks on the select, but when user selects an option the option should be displayed "normally" (ie with no leading spaces).
Attempted solution using JS and Jquery: My JS is far from sophisticated so I apologize in advance :)
I attempted to use .on("change") and .on("click") to change the selected option value (by calling .trim() since I achieve the "nested" structure with ). I'm also storing the original value of the selected option because I want to revert the select menu to its original structure in case the user selects another option.
The problem: The function registered for .on("click") is called twice, thus the select value immediately resets itself to its original value.
I suspect there is a much, much easier solution using CSS. I will be happy to accept an answer that will suggest such solution.
JSFiddle: https://jsfiddle.net/dv6kky43/9/
<form>
<select id="select">
<option value=""></option>
<option value="a"> a</option>
<option value="b"> b</option>
</select>
</form>
<textarea id="output"/>
var orig;
var output = $("#output");
output.val("");
function onDeviceSelection(event){
output.val(output.val() + "\nonDeviceSelection");
var select = event.target;
orig = select.selectedOptions[0].text;
select.selectedOptions[0].text = select.selectedOptions[0].text.trim()
}
function resetDeviceSelectionText(event) {
output.val(output.val() + "\nresetDeviceSelectionText");
var select = event.target;
if (orig !== undefined){
select.selectedOptions[0].text = orig;
}
}
$("#select").on("change", onDeviceSelection);
$("#select").on("click", resetDeviceSelectionText);
If you are already using jQuery, why not utilize data function to store the original value. This way you will also be able to specify different nest levels.
(function($){
$(document).on('change', 'select', function(event) {
$(this).find('option').each(function(index, element){
var $option = $(element);
// Storing original value in html5 friendly custom attribute.
if(!$option.data('originalValue')) {
$option.data('originalValue', $option.text());
}
if($option.is(':selected')) {
$option.html($option.data('originalValue').trim());
} else {
$option.html($option.data('originalValue'));
}
})
});
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
<select id="select">
<option value=""></option>
<option value="a"> a</option>
<option value="b"> b</option>
</select>
</form>
Once caveat I see is, the selected option will appear trimmed on the list as well, if dropdown is opened after a previous selection has been made:
Will it still work for you?
Instead of keeping the state of the selected element i would simply go over all options and add the space if that option is not selected:
function onDeviceSelection(event){
// Update textarea
output.val(output.val() + "\nonDeviceSelection");
// Higlight the selected
const {options, selectedIndex} = event.target;
for(let i = 0; i < options.length; i++)
options[i].innerHTML = (i === selectedIndex ? "":" ") + options[i].text.trim();
}
$("#select").on("change", onDeviceSelection);
Note that you need to use innerHTML to set the whitespace...

How to get the text attribute of a dropdown

I am wondering how I can retrieve the text of the selected item in a dropdown using JQuery. Currently the code I have retrieves the value and I actually need the text associated with that value.
This is my code:
var stockCode = $(this).closest('li').find('.stock_code').html();
var quantity = $(this).closest('li').find('.order_amount').val();
var growers = $(this).closest('li').find('.growers').val();
var sharequantity = $(this).closest('li').find('.share_amount').val();
This is HTML
<span class="bulk" style="">
<select name="CMP Member" id="CMP Member" class="growers">
<option value="0">Choose Grower to Share...</option>
<option value="10">xxxxx</option>
<option value="25">xxxxx</option>
<option value="4">xxxxxx</option>
<option value="6">xxxxxx</option>
</select>
I required the text at xxxxx...
Many thanks for any help. Also must point out I've got multiple dropdowns being generated dynamically so I would need to reference it by class.
Try this:
$('.growers option:selected').text()
Use val() for the option value attribute and text() for the text inside the option:
$(".growers option:selected").text();
You have to get it by using the :selected selector along with the .text() function
var growers = $(this).closest('li').find('.growers option:selcted').text();

Retrieving the text of the selected <option> in <select> element

In the following:
<select id="test">
<option value="1">Test One</option>
<option value="2">Test Two</option>
</select>
How can I get the text of the selected option (i.e. "Test One" or "Test Two") using JavaScript
document.getElementsById('test').selectedValue returns 1 or 2, what property returns the text of the selected option?
function getSelectedText(elementId) {
var elt = document.getElementById(elementId);
if (elt.selectedIndex == -1)
return null;
return elt.options[elt.selectedIndex].text;
}
var text = getSelectedText('test');
If you use jQuery then you can write the following code:
$("#selectId option:selected").html();
document.getElementById('test').options[document.getElementById('test').selectedIndex].text;
Under HTML5 you are be able to do this:
document.getElementById('test').selectedOptions[0].text
MDN's documentation at https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/selectedOptions indicates full cross-browser support (as of at least December 2017), including Chrome, Firefox, Edge and mobile browsers, but excluding Internet Explorer.
selectElement.options[selectElement.selectedIndex].text;
References:
options collection, selectedIndex property: HTML DOM Select Object
text property: HTML DOM Option Object
exactly the answer of this question: Option text Property
The options property contains all the <options> - from there you can look at .text
document.getElementById('test').options[0].text == 'Text One'
You can use selectedIndex to retrieve the current selected option:
el = document.getElementById('elemId')
selectedText = el.options[el.selectedIndex].text
this.options[this.selectedIndex].innerText
If you found this thread and wanted to know how to get the selected option text via event here is sample code:
alert(event.target.options[event.target.selectedIndex].text);
Use the select list object, to identify its own selected options index.
From there - grab the inner HTML of that index.
And now you have the text string of that option.
<select onchange="alert(this.options[this.selectedIndex].innerHTML);">
<option value="">Select Actions</option>
<option value="1">Print PDF</option>
<option value="2">Send Message</option>
<option value="3">Request Review</option>
<option value="4">Other Possible Actions</option>
</select>
The :checked selector can be used with document.querySelector to retrieve the selected option.
let selectedText = document.querySelector('#selectId option:checked').text;
// or
let selectedText = document.querySelector('#selectId')
.querySelector('option:checked').text;
document.querySelector('button').addEventListener('click', function(e) {
console.log(document.querySelector('#selectId option:checked').text);
});
<select id="selectId">
<option>a</option>
<option>b</option>
<option>c</option>
</select>
<button>
Get selected text
</button>
For select elements with the multiple attribute, document.querySelectorAll can be used to obtain all selected options.
let selectedText = [...document.querySelectorAll('#selectId option:checked')]
.map(o => o.text);
document.querySelector('button').addEventListener('click', function(e) {
let selectedText = [...document.querySelectorAll('#selectId option:checked')]
.map(o => o.text);
console.log(selectedText);
});
<select id="selectId" multiple>
<option>a</option>
<option>b</option>
<option>c</option>
</select>
<button>
Get selected text
</button>
Similar to #artur just without jQuery, with plain javascript:
// Using #Sean-bright's "elt" variable
var selection=elt.options[elt.selectedIndex].innerHTML;
Easy, simple way:
const select = document.getElementById('selectID');
const selectedOption = [...select.options].find(option => option.selected).text;
It is pretty simple. In javascript anything with an ID doesn't need document.queryselector or $('#test') you can just use test. Then you simply loop over the selectedOptions which is apart of javascript and you can add it to a new array and use that data how ever you want.
let selectedItems = [];
for ( var i = 0; i < test.selectedOptions.length; i++) {
selectedItems.push(test.selectedOptions[i].text);
}
Also
// if you want values
selectedItems.push(test.selectedOptions[i].value);

Categories

Resources