How to get option value of select element - angularjs

I am trying to get the option value of a select element using Protractor. However, I'm not able to find the option element.
HTML
<select ng-options="opions.c as options.n for option in options" ng-model="model">
<option value="0">Option 1</option>
<option value="1">Option 2</option>
</select>
Spec-file
describe('testing select option', function() {
it('', function() {
ptor = protractor.getInstance();
//This will not get the option required
ptor.findElement(protractor.By.binding('model'));
});
});
I cannot seem to find a way to grab the option value as I haven't found a function that I can use that doesn't give and exception or error message.
Does anyone know how to resolve this issue?

I have had some problems getting dropdowns working well, and have spent some time today working it out (and therefore I'm sharing it here in case someone else finds it useful).
On earlier versions of Protractor there was a by.selectedOption, which effectively does the same thing as by.select, but returns only the selected item. So, to get the text of the selected option above, you could have:
expect(element(by.selectedOption('model')).getText()).toEqual('Option 1');
I wrote a blog post if you want more detail, it also covers a helper function for selecting the option in the dropdown: http://technpol.wordpress.com/2013/12/01/protractor-and-dropdowns-validation/
Recent versions of protractor have removed this function, replacing it with:
expect(element(by.id('my_id')).element(by.css('option:checked')).getText();
Which is more flexible, as it can be applied to any of the finders, whereas selectedOption only worked with a model finder.

ok again I have now been able to figure out how to grab the option element with protractor.
the example code below shows how to accomplish this.
ptor.findElement(protractor.By.css('select option:nth-child(value of the option you require IE: the number)')).click();

Try using xPath:
ptor.findElement(protractor.By.xpath('//select/option[1]'));
You can use the same technique to choose an option by value:
protractor.By.xpath('//select/option[text()="Option 2"]'));
I've needed to do this for setting up forms where inputs are visible based on selected dropdowns, e.g.:
makeFord = protractor.By.xpath('//select[#id="make"]/option[text()="Ford"]'));
modelMustang = protractor.By.xpath('//select[#id="model"]/option[text()="Mustang"]'));
makeFord.click();
modelMustang.click();

Here is how you can get the value of an option in a select:
HTML
<select ng-options="opions.c as options.n for option in options" ng-model="model">
<option value="Africa">Option 1</option>
<option value="Switzerland">Option 2</option>
</select>
.spec file
describe("Country <select>", function() {
it("should have 'Africa' as the value of the first option", function() {
browser.get('index.html');
let all_options = element.all(
by.options("opions.c as options.n for option in options") //use whatever string is assigned to the ng-options attribute in the html
);
let first_option = all_options.get(0); //or all_options.first()
let second_option = all_options.get(1); //or all_options.last()
expect(
first_option.getAttribute('value')
).toEqual("Africa");
});
});
To get the value of a selected option (which can be an option programmatically selected with protractor by calling click() on an option):
expect(
element(
by.model('model') //'model' is the string assigned to the select's ng-model attribute
).element(
by.css('option:checked')
).getAttribute('value')
).toEqual('Swizerland');

This will help.
//check whether the selected value is equal to the expected value.
expect(element(by.model("model")).getAttribute('value')).toEqual("0");
//catch the selected value
element(by.model("model")).getAttribute('value').then(function (value) {
console.log('selected value', value);
});

In order to enumerate the option tags you can try to use the .all method and you should access it by the parent first.
element(by.model('model')).all(by.tagName('option')).then(function(arr) {
expect(arr.length).toEqual(2);
});
Have a look at the API reference for inspiration
http://www.protractortest.org/#/api?view=ElementArrayFinder.prototype.all
Edit: also follow the style guide which discourages usage of XPath
http://www.protractortest.org/#/style-guide

Related

AngularJS Multiple Select not showing preselected options

I have been most part of the morning working on a solution for when I need to assign several values to an entity on my form.
So, the idea is I have an Entity called QualityData and this entity can have different MechanismIdentifiers.
Best solution I thought of, use a multiple select.
All works fine combining both these solutions:
AngularJS selecting multiple options
Get value when selected ng-option changes
I can access the array of selected options, assign it to my entity, etc... But I have a "minor" fallback, which is that I can't get the preselected options (the ones that would come from the server when loading data for editing) to be highlighted in the select field when using a dynamic approach such as <option ng-repeat> or ng-options, it will only work when hardcoding the options. Another bug is that if I wish to add more values than those that are in the preselected array, it will erase all values present in it when using a dynamic approach, working fine when harcoding.
The markup:
<select multiple ng-change="showAlert(selectedValues)" ng-model="selectedValues">
<!--ng-options="resDatasIdOfMechanism as resDatasIdOfMechanism.name for resDatasIdOfMechanism in resDatasIdOfMechanisms track by resDatasIdOfMechanism.id" value="resDatasIdOfMechanism.id">-->
<option value="1">{{resDatasIdOfMechanisms[0].name}}</option>
<option value="2">{{resDatasIdOfMechanisms[1].name}}</option>
<option value="3">{{resDatasIdOfMechanisms[2].name}}</option>
</select>
If I try to use the line that is commented, it's when the marked option will not work
The controller:
$scope.selectedAlready = [{id:1, name:"Based on Antibiogram"}];
$scope.selectedMechanisms=[];
$scope.resDatasIdOfMechanisms = [{id:1,name:"Based on Antibiogram"}, {id:2,name:"Molecular"}, {id:3,name:"Genetic"}];
$scope.selected = $scope.selectedAlready;
$scope.selectedValues = [];
$scope.$watch('selected', function(nowSelected){
$scope.selectedValues = [];
if( ! nowSelected ){
return;
}
angular.forEach(nowSelected, function(val){
$scope.selectedValues.push( val.id.toString());
console.log("look");
});
});
$scope.showAlert=function(listOfMultipleChoices){
//alert(object);
}
EDIT to add jsfiddle link which is working but I still haven't found solution to original question: https://jsfiddle.net/StevenEvenSteven/ybapx09w/
There is a typo in your code.
Add a comma after '$scope' in your controller definition
fiddleApp.controller('myFiddle', ['$scope', function($scope) {
I've forked your jsfiddle and it is working as you expected.

Adding angular directives to simple_form in rails breaks selected option for collection input

Not sure if there's a workaround for this, I'm doing something wrong, or this is a collision between simple form or angular, but:
.field
= f.input :role, collection: roles.map(&:name), selected: user.role.try(:name), include_blank: 'Select', required: true, input_html: { "ng-model" => "role" }
renders (which looks correct):
<select ng-model="role" class="select required" name="user[role]" id="user_role">
<option value="">Select</option>
<option value="system">system</option>
<option selected="selected" value="fcm">fcm</option>
<option value="regulatory">regulatory</option>
<option value="operations">operations</option>
<option value="help_desk">help_desk</option>
</select>
But the selected value is the include_blank value of 'Select'. And yes, role is set on the user.
The reason it's doing this is because of the way angular models work and it requires an understanding of this. Essentially the ruby generates the select correctly choosing the selected option of the select box too.
However, once the angular is loaded and sees ng-model on this select it sets the current selected option to the value of the model, in your case, role.
Thus if you want to have an angular model for this select, you need to set the initial value of that model.
Try the following:
.field
= f.input :role, collection: roles.map(&:name), include_blank: 'Select', required: true, input_html: { "ng-model" => "role", "ng-init" => "role = #{user.role.try(:name)}" }
Note that the selected option has been removed entirely since this will be controlled by the Angular model, which is initialized to that value using ruby string interpolation.
I thought for a moment on this particular example and I am not quite sure what you expected to happen with the result.
Although, I assumed that you want to have option with attribute selected="selected" selected as a default value, instead of value="", which is only a blank field. If that I understood correctly and this is the point, that means there are several fields, which might be incorrect and We (the community) do not know how you completed them, but I think I dug up for the problem... ;)
Angular directive - At first, I do not know which version of angular you used in the example (I assume 1.X, because question have 6 months from this moment). The AngularJS select directive overrides the default behavior of select element and change it a bit.
I prepared a simple example with Angular v1.0.1 for the tests and it looks behave correctly in few aspects. If you use ng-model="role" and set the role to fcm (String), like $scope.role = 'fcm', the angular is obligate to set this value if it will find it.
I have also tested (AngularJS v1.0.1) what if the role is not set (undefined), then angular also point on empty string value like value="" and it not see into attribute selected and not set it as default. In the other side, the latest stable AngularJS v1.5.6 does support selected attribute example with AngularJS v1.5.6, so it might be the core of the problem.
Well, the solution for this is simple:
upgrade AngularJS for the latest 1.X version or
consider to use
ngSelected
or ngInit/SO
solution instead if the version AngularJS you used support that.

Dynamic Select List Default Selected Item - Angular JS

I have the code listed below which works fine, however when i attempt to add ng-model and related ng-change to the select, an empty option is added. I understanding why, it is because on init the selectedOption for ng-model is empty.
What I want to do is set a default value so when I can use ng-change to set options IsSelected value to true when user selects it. I'm just not sure how to go about this, I have no issues doing this when I'm working with a static generated select list, but for some reason I can't figure it out for this dynamic generated list.
Any input is appreciated!
<div ng-repeat="optionType in productDetailModel.OptionTypes">
<select name="{{optionType.OptionTypeName}}">
<option ng-repeat="option in optionType.Options"
value="{{option.OptionValue}}">{{option.OptionValue}}
</option>
</select>
</div>
Here's plunkr I mocked to give a basic idea of what I have in mind: http://plnkr.co/edit/xBDfc0XzDwsF0mBiFZOv?p=preview
The initial option is blank because the model is initially undefined.
As tymeJV said, initializing your scope inside of your .js will define a default value that will be shown as selected initially.
$scope.modelName = $scope.optionType.Options[0];
It might be helpful to use ng-options instead of ng-repeat. One reason why it might be beneficial is that ng-options does not create a child scope (unlike ng-repeat). This could help simplify linking to your model and avoid confusion.
<select name="{{optionType.OptionTypeName}}" ng-model="modelName" ng-options="option for option in optionType.Options">
</select>
This article covers the basics of ng-options as well as discusses why it would be used as opposed to ng-repeat.
Hope this helps.
Use ng-options when using a select!
<select name="{{optionType.OptionTypeName}}" ng-model="someModel" ng-options="option as option for option in optionType.Options>
</select>
And then set the ngModel to the default option you want selected:
$scope.someModel = $scope.optionType.Options[0]
There is one directive of select element is ng-init but it call once while first time rendering, but if you change the options dynamically then it will not call again. So for that you need to set the model field with value in scope just below of your new option population logic.
$scope.modelName = $scope.Options[0]; // if array
$scope.modelName = $scope.Options[key]; // if Json Object

Using ng-selected with a <select>

I'm trying to send some piece of information to my loadSecondary function, but I don't know how to access any information about my array or the object I'm selecting.
I've tried sending $index,p,$parent.$index,$parent.p, and all of them come out as undefined.
What information about my selected object or it's position in the array can I send to my function?
<select ng-model="secondPres" ng-options="p.name for p in presentations">
<option value="" ng-selected="loadSecondary(???)">-- Choose a presentation to merge with --</option>
</select>
Rather than use ng-selected, I would put a watch on the $scope.secondPres in your controller, then run loadSecondary on it:
$scope.$watch('secondPres', function(s) {
if(typeof s !== 'undefined') {
$scope.loadSecondary(s);
}
});
Since I couldn't send anything with ng-selected, I sent nothing.
I ended up just accessing $scope.secondPres, from the inside the function

How can I detect when a USER changes the value in a select drop down using AngularJS?

I have the following:
<select data-ng-model="selectedTestAccount" data-ng-options="item.Id as item.Name for item in testAccounts">
<option value="">Select Account</option>
</select>
It was suggested to me that I could watch for the value of this select to change with the following:
$scope.$watch('testAccounts', function(){
/* get updated values and update other select "model" on success*/
alert("hello");
});
But this does not seem to work. For one thing it gives an alert as soon as the select appears on the screen and before the user has selected anything. Also am I correct in saying that I should be watching for a change in selectedTestAccount? Finally one more question. How can I show the value of selectedTestAccount in an alert box?
As said, you can get it as the first argument, no need to get it from scope. Use
$scope.$watch('selectedTestAccount', function(newValue){
alert(newValue);
});
Beware that you always get a undefined as the first change for a $watch.
What about putting an "ng-change" to your select?
In your example it would be something like this:
<select data-ng-model="selectedTestAccount" ng-change="updateSelectedAccount(selectedTestAccount)" data-ng-options="item.Id as item.Name for item in testAccounts"></select>
And then in your controller
$scope.updateSelectedAccount = function (selectedTestAccount) {
console.log(selectedTestAccount);
}
P.S. Sorry, just noticed how old this question is :) Hope this might help somebody in the future.

Resources