I'm unable to find drop-down list on webpage. Help to locate it and create the method for it.
Following is the code -
<select name="equipment_type" class="smalltext0" onchange="return submitByFormNameAndAction('featureAddChangeForm','FeatureAddChangeValidateMobile.do')">
<option class="device" selected="" value="P">iPhone</option>
<option class="device" value="Z">Blackberry</option>
<option class="device" value="3">Android</option>
</select>*
Previous Answer + new stuff:
#Findby(css = "#id")
private Webelement selectElement;
public Select getPageSelectElement(){
return new Select(selectElement);
}
Would be cool if we could get it directly from PageFactory though.
You probably want something like this in your PageFactory:
#FindBy(how = How.NAME, using = "equipment_type")
WebElement selectElement
...
Select getPageSelectElement(){
return new Select(selectElement);
}
You can then use the getPageSelectElement function to return a Select object from your page factory that can be used in your test.
Please note that the above is not code for a full page factory, just the bits you need to add to your page factory to find and return the Select element.
Related
I'm currently working on an application that displays some movies. I have an API that successfully retrieves the movies and also has the option to get movies by a specific genre. For that I've created a Select element with the different genres dynamically loaded in. When one of the genres is clicked I want to update the movies by using the API to only get the movies in the selected genre.
Unfortunately, nothing happens when I select an option. Please note that I have confirmed that the API calls work so it has to be something in this code.
This is the HTML-element:
<div class="content px-sm-3">
<select>
<option onselect="async () => await changeMoviesByGenre('None')" value="None">None</option>
#foreach (var genre in genres)
{
<option value=#genre onselect="async () => await changeMoviesByGenre(genre)">#genre</option>
}
</select>
</div>
and this is the function that should be called:
private async Task changeMoviesByGenre(string genre) {
if (genre == "None") {
movies = await MovieClient.Movies.GetAll();
}
else {
movies = await MovieClient.Movies.GetAllMoviesByGenre(genre);
}
}
OnSelect isn't what you think it is. It's triggered when you select text in an Input element.
The simpler way (as you have covered in answering your answer and I've included as a full working page for completeness in the answer) is:
#page "/Test"
<div class="content px-sm-3 m-2">
<select #onchange="OnChange">
<option value="None">None</option>
#foreach (var genre in genres)
{
<option value="#genre">#genre</option>
}
</select>
</div>
<div class="m-2">Selected: #SelectedGenre</div>
#code {
private List<string> genres
=> new List<string>() { "Rock", "Folk", "Blues", "Pop" };
private string SelectedGenre = string.Empty;
private async Task OnChange(ChangeEventArgs e)
{
var selected = e.Value.ToString();
SelectedGenre = "Getting it, just wait!!!";
await Task.Delay(3000);
if (selected.Equals("None", StringComparison.CurrentCultureIgnoreCase))
this.SelectedGenre = "Give it another Go!";
else
this.SelectedGenre = selected;
}
}
#Onxxxx (such as #OnChange and #OnClick) are UI events. They are run by the UI process before re-rendering on the component. A Task event handler is run by the UI and awaits the Task before updating the UI. A void event handler is started by the UI process, and if/when it yields updates the UI (a lot more complicated and unpredictable). You can use these code patterns dependant on your needs:
async void MyEventHander() {}` //for handlers that need to do async work and you don't need the UI process to wait on the completion of the handler.
async Task MyEventHander() {}` //for handlers that need to complete before re-rendering.
void MyEventHander() {}` //for handlers with no async work.
In my example I've added await Task.Delay(1000); to simulate an async database call so I can declare the handler as async.
Note:
e in OnChange is an object, so you can cast it to what you are expecting.
None is already selected on initialization, so if you select it first, there's no OnChange because nothing has changed.
See Ms Docs - Blazor Event Handling.
I have managed to fix the problem somehow.
If you're having the same problem that I had, I fixed it by using this example I do not know why it works, but it does.
I'm not using the values from the foreach but instead I'm now using the ChangedEventArgs parameters. I also set the onchange to the Select element and not the Options elements. This is how my code now looks:
<div class="content px-sm-3">
<select #onchange=#changeMovies>
<option value="None"> None </option>
#foreach (var genre in genres) {
<option value=#genre> #genre </option>
}
</select>
</div>
and this is the new function that gets called (please note that this has to be a task otherwise the page won't get updated)
private async Task changeMovies(ChangeEventArgs e) {
string selectedGenre = e.Value.ToString();
if (selectedGenre == "None") {
movies = await MovieClient.Movies.GetAll();
}
else {
movies = await MovieClient.Movies.GetAllMoviesByGenre(selectedGenre);
}
}
So I came across this post regarding this similar question, https://stackoverflow.com/a/48078627 the answer was correct but it is in javascript, how can I transform it into the way how react will handle this piece of code.
Below is the code in javascript
<select id="sel" onchange="ChangeList()">
<option value="">select</option>
<option value="I">Integer</option>
<option value="A">Alphabet</option>
</select>
<select id="type"></select>
<script>
var IntandAlph = {};
IntandAlph['I'] = ['1', '2', '3','4','5','6','7','8','9','10'];
IntandAlph['A'] = ['A', 'B', 'C', 'D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
function ChangeList() {
var selList = document.getElementById("sel");
var typeList = document.getElementById("type");
var seltype = selList.options[selList.selectedIndex].value;
while (typeList.options.length) {
typeList.remove(0);
}
var Num = IntandAlph[seltype];
if (Num) {
var i;
for (i = 0; i < Num.length; i++) {
var sel = new Option(Num[i], i);
typeList.options.add(sel);
}
}
}
</script>
</body>
</html>
I am new to React and web development as well, it would be great if you can enlighten me on this issue. Thanks a lot in advance.
I have created a sample using useState and useEffect hooks to achieve the desired behavior, but there are plenty other ways to do it.
At start, I am declaring options as a constant object, with keys equal to the values of the the first select.
EDIT 2: After author's request, I've updated my sample fetching data from remote server instead of using a constant.
Then using useState I handle the user selection of the first select. When this value change, I look into my data state, for the appropriate array of data.
I strongly recommend you to take a look to React hooks for more details.
EDIT: I've added some comments on the code provided, explaining step by step the process.
You can store the value of the first dropdown into the state upon selecting on the first dropdown.
And then you base the options of the second dropdown on the state.
I have tried to search both the forum and Google extensively, but I have problems understanding how I should make this work:
PrimeFaces6
I have a BarchartModel based on the tutorial in the ShowCase:
CODE: SELECT ALL
private BarChartModel initStatusBarChart() {
BarChartModel model = new BarChartModel();
ChartSeries statusMessages = new ChartSeries();
statusMessages.setLabel("Label"));
statusMessages.set("Some String 1", list1.size());
statusMessages.set("Some String 2", list2.size());
model.addSeries(statusMessages);
return model;
}
The issue is that on render, I get tooltips the format of
"1, 515" and "2, 432", where 515 and 432 are the sizes of list1 and list2, respectively.
How can I replace 1 and 2 with the values "Some String" 1 and 2 ? Have tried extending highlighter and using dataTipFormat, with no success.
I solved the problem using the datatip editor of the chart model (with Primefaces 6.1, by the way). I used this for a stacked bar chart.
I needed to apply this solution at two places: the backing bean and the JSF page.
In the backing bean I had to set a JavaScript function name this way:
barModel.setDatatipEditor("chartDatatipEditor");
I tried to set it using the corresponding tag attribute in the JSF page but to no effect.
In the JSF I inserted this JavaScript code:
<script type="text/javascript">
function chartDatatipEditor(str, seriesIndex, pointIndex, plot) {
//console.log('chartDatatipEditor: '+str+" - "+seriesIndex+" - "+pointIndex);
var point = seriesIndex+','+pointIndex;
#{bean.datatipsJs}
}
</script>
This JS function gets the chart coordinates as parameters. I concat them so that the following JS code gets easier.
seriesIndex is the index of the chart series. pointIndex is the index on the X scale of the diagram.
To find out what are the correct values for your chart you can uncomment the console.log line above.
The inserted JS code is constructed in the backing bean this way:
private Map<String, String> chartDatatips;
public String getDatatipsJs() {
StringBuilder sb = new StringBuilder("switch ( point ) {\n");
for (String point : chartDatatips.keySet()) {
sb.append("case '").append(point).append("': return '").append(chartDatatips.get(point)).append("'; break;\n");
}
sb.append("default: return 'Unknown point'; break; }");
return sb.toString();
}
The map chartDatatips has the coordinate point as key (e.g., "2,1") and the tooltip as value.
During the chart setup you obviously have to fill this map with useful details ;-)
Like this:
chartDatatips.put("2,5", "Label ...");
...
Hope this helps, if you didn't already solved this.
~Alex
Based on Alex's answer I have come up with this. Only requiring javascript - it displays the label and value:
In the backing bean, set a JavaScript function name this way:
barModel.setDatatipEditor("chartDatatipEditor");
In the HTML file:
function chartDatatipEditor(str, seriesIndex, pointIndex, plot) {
return plot.series[seriesIndex].label + ' - ' + plot.data[seriesIndex][pointIndex];
}
I have a country dropdown and I set the selected attribute to US. I can clearly see select="selected" into select OPTION having value US in firebug. But neither firefox or chrome shown US as selected.
I have code for populate & selected country as follows.
var countryData = getCountryData();
var html = '<option value="">Select Country</option>';
$.each(countryData, function(key,value) {
if(defaultValue == value.id)
{
html = html + '<option value="'+value.id+'" selected="selected">'+value.name+'</option>';
}
else
{
html = html + '<option value="'+value.id+'">'+value.name+'</option>';
}
});
countryField.html(html);
If it is really possible for any reason to browser not shown the selected even we set the attribute selected.
UPDATE : Ok guys, As I was expecting it must be conflicted by other code. And that is the case . I am using bootstrapValidator and a special call "resetForm" which did this behavior. However one thing I did not understand why still html select in firebug shown selected attribute ? But at last I placed this code after resetForm call. Thanks to all for suggestions & help.
I had this peculiar problem of multiple select not selecting the selected values. What I ended up doing is select them with JS (I have jQuery in my app, so that makes it easier) like so:
$('#select_element').find('option[selected="selected"]').each(function(){
$(this).prop('selected', true);
});
I know this is ugly, and it should be avoided, but if nothing works, this WILL work.
you dont need to set selected="selected", selected itself is sufficient
<option value="anything" selected>anything</option>
Also check, is your HTML markup is correct. You are closing the <option> with </value>. It is wrong, should be <option></option>
EDIT
If the above solution is not working, you could set it through JavaScript:
document.getElementById("idOfSelect").selectedIndex = "1";//index starts from 0
This works for me but you can try this:
countryField.html(html).trigger('change');
you don't need selected="selected" just value.id + ' selected>' + ...
also it should be not
lastly, check that
defaultValue == value.id
in the debugger.
I had a similar issue but in my case it was not JS, but the GET variable value of another option matched the name of an option and that didn't work.
So: https://example.com?section=instruments&instruments=0 failed. Renaming to unique names fixed it for me.
Apologies if this has already been mentioned or answered but I have looked for a few days and cannot work this out. I am new to both Knockout and StackOverflow so bear with me please.
I am working with CakePHP and have some JSON returned from my controller which is in the following format
{"countries":[{"Country":{"id":"1","country":"England"}},{"Country":{"id":"2","country":"Wales\/Cymru"}},{"Country":{"id":"3","country":"Scotland"}},{"Country":{"id":"4","country":"Republic of Ireland"}},{"Country":{"id":"5","country":"Northern Ireland"}}]};
I am hoping to have the above counties appear as an item in a select statement with the value being set to 1 and the text displayed as the country. However I cannot seem to get knockout to do this for me. I am sure this is a simple question to those familiar with knockout but I cannot understand what to do all I see is the list of objects but do not know how to access the object properties on the data-bind
HTML
<select data-bind="options:countries, optionsText:'Country'"></select>
Javascript
var viewModel = {};
var data = {"countries":[{"Country":{"id":"1","country":"England"}},{"Country":{"id":"2","country":"Wales\/Cymru"}},{"Country":{"id":"3","country":"Scotland"}},{"Country":{"id":"4","country":"Republic of Ireland"}},{"Country":{"id":"5","country":"Northern Ireland"}}]};
var jsData = ko.mapping.fromJS(data);
ko.applyBindings(jsData);
I have created a simple JSFiddle http://jsfiddle.net/jbrr5/14/ to show what is happening any help would be appreciated with this small challenge
Your data has an odd structure. It's like this:
- countries
- Country
- id
- country
The actual id and country is another level deep in the array of countries. You'd have to do some hacking around just to get those to appear in the select element as-is. It would be better if you just mapped to the inner Country objects.
var mappingOptions = {
'countries': {
'create': function (options) {
// map to the inner `Country`
return ko.mapping.fromJS(options.data.Country);
}
}
};
var viewModel = ko.mapping.fromJS(data, mappingOptions);
ko.applyBindings(viewModel);
Updated fiddle
You have very complex structure of array. For your case you have to write 'Country.country' in options binding but it doesn't work because binding cannot parse such complex expression. Instead of using options and optionsText bindings you can use foreach:
Here is working fiddle: http://jsfiddle.net/vyshniakov/jbrr5/18/
But I would recommend you change structure of your data to
{"countries":[{"id":"1","country":"England"}]};
or map data accordingly. In this case you could use options binding:
<select data-bind="options:countries, optionsText:'country', optionsValue:'id'"></select>