Can't get Angular select to update with selected value - angularjs

I'm using selects to allow a user to switch between events and years. Each change will pull appropriate data from the server, return and update the page. However, the select box goes from the selected value to an empty value. I've looked at numerous solutions and they aren't working.
<select
ng-model="eventName"
ng-options="item.value for item in eventOptions track by item.value"
ng-change="changeEvent(eventName.value)">
</select>
This is the changeEvent function:
$scope.changeEvent = function(eventName){
$scope.eventName = eventName; //wrongly assumed this would update the selected value
$scope.getData($scope.eventName,$scope.eventYear); //this returns the json - correct
$scope.updateSelected(); //meant to update the select field value on the page - fails
};
$scope.eventName or $scope.eventYear values will properly update on a change, but has no effect on the page. The selects just empty of a selected value.
UPDATED (with corrected code)
I wanted to post the changes I made more clearly than the comment allows.
I removed the object param "value" from the options and the argument from the function call (eventName.value).
<select
ng-model="eventName"
ng-options="item for item in eventOptions track by item"
ng-change="changeEvent()">
</select>
And the changeEvent function gets simplified to:
$scope.changeEvent = function(){
$scope.getData($scope.eventName,$scope.eventYear);
};
It all works as expected! Thanks to all, especially Delta who got me looking at it the right way.

So, your event name variable is set to be item. not item.value so instead of passing in changeEvent(eventName.value) try passing in changeEvent(eventName). either way the value you are passing into your method doesnt match the value of your model's variable
item.value for item in eventOptions track by item.value
so for this statement, you are saying make my options ng-model=item but make their value=item.value so they show what you want them to show but still have all the information you need from each one.
Upon further inspection is looks like you dont need:
$scope.eventName = eventName;
$scope.updateSelected();
Angular should be updating your eventName for you, you just need to call the change method.

I'm not sure you need:
ng-change="changeEvent(eventName.value)"
if you use ng-options the model will be updated in the scope automatically on selection. You could watch the value in the controller if you want to do other stuff when it changes:
$scope.$watch('eventName', function() {
//do stuff
});

Related

AngularJS Dependent dropdown with ng-repeat is leaving blank

I am trying to make a dependent dropdown but somehow the second dropdown is always leaving a blank if i am changing the first dropdown.
<select class="form-control DB_Control" id="Sector" ng-model="selected_sector" ng-init="selected_sector = initial_selected_sector" ng-options="each.sector for each in data track by each.sector" ng-change="getSubsector()">
<select class="form-control DB_Control" ng-model='related_subsector3' ng-options="subsector for subsector in sub_sectors track by subsector" >
$scope.getSubsector = function() {
$scope.related_subsector3 = $scope.sub_sectors[0]
}
Just for more information, if i am printing the value of $scope.related_subsector3 in function getSubsector, its printing correct value but its not setting the value in template.
I don't think that would work. What I would try is to create another function called "$scope.getSubSectorChildren()" which would populate the second dropdown on the change of the first one. That way you can keep the data population more flexible and it would be easier to test/debug.

Angular - Select fields don't update when value received via $http

I have two select fields, one for Month and one for Day (controller as name is 'contactDetails'):
<select
data-ng-model="contactDetails.contactBasicInfo.bdmonth"
data-ng-options="bdMonth.key as bdMonth.value for bdMonth in contactDetails.months">
<option value="">Month</option>
</select>
<select
data-ng-model="contactDetails.contactBasicInfo.bdday"
data-ng-options="bdDay.key as bdDay.value for bdDay in contactDetails.days">
<option value="">Day</option>
</select>
That output the selects just fine and I can use them to save information to the database. No problems there.
The issue is when I pull the info back out of the database and want the select fields to update to reflect the values pulled from the database. They don't. If I hard-code the values into the controller, they'll update, but not if the values are assigned after an $http call.
I have this at the top of the controller to set up the defaults:
ctrl.contactBasicInfo.bdmonth = 0;
ctrl.contactBasicInfo.bdday = 0;
And later I call a function that then assigns values to those two variables:
ctrl.contactBasicInfo = data.contactInfo.contactBasicInfo;
All other data that comes out of data.contactInfo.contactBasicInfo works and the fields update, like firstName, phone, email, etc. If I place the models in the html like {{ctrl.contactBasicInfo.bdmonth}}, it will show the correct values. So, I know the values are coming back correctly from the $http call. The selects just don't change to reflect the new values.
Any ideas what I am missing?
Thanks!
It's because the directive ngModel for a <select> element uses the === comparison when binding. Hence 0 === '0' will return false. So you should assign a string not a number/integer to your ngModel attached to the dropdown.

AngularJS changing the selected OPTION in a SELECT list based on a predefined value

I have a select list which is rendered via an ng-repeater and on change it fires the value of the selected option into a function this works as expected.
The issue I am now stuck on is if the page is loaded with a specific option requested how I ensure that select option is highlighted.
I have it so the GUID which is the value of the select is automatically fired to the function to get the page data for the selected item so that's working the issue is highlighting the selected item in the select list to show the user its related to that selection.
My code is below but you will see that I am binding it to ng-model="asCtrl.accSelected" which passed the GUID value. My assumption was that when a predefined GUID is requested I can set vm.accSelected to be equal to the GUID value and that should due to the 2 way binding show the selection on the select list but this doesn't seem to be the case.
<div data-ng-controller="tpAccStatusCtrl as asCtrl">
<select class="form-control" ng-model="asCtrl.accSelected" ng-change="asCtrl.retrieveAccount(asCtrl.accSelected)">
<option value="select" selected="selected">Select an Account</option>
<option ng-repeat="acc in asCtrl.accounts" value="{{acc.UniqueIdentifier}}">{{acc.AccountName}}</option>
</select>
</div>
I hope the above makes sense and someone can show me how to ensure the select list reflects the value set for vm.accSelected
Call the asCtrl.retrieveAccount(asCtrl.accSelected) function manually on page load. Ng-change will only trigger if the value is changed by the input, if I'm not mistaken.

Roll back ngOptions select to unselected state

ngOpions creates a blank option like option html below if the model value doesn't match any of the option values:
<option value="?" selected="selected"></option>
After a selection is made, AngularJS removes this first empty option html from the select html.
I have a use case where I want to roll back the state of the html select to the unselected option which AngularJS removed. I tried ngModel methods like $setPristine(), $rollbackViewValue(), and $setUntouched(). But none of these mothods puts the state of the select back to the initial state with the empty option.
Is it possible to truely roll back an AngularJS select element to have the empty option after a selection is made?
The code for ngOptions (line 473 in ngOptions.js ) suggests that only single-select can get it, and that the writeValue function (called when the ngModel changes) has to be invoked with a null value (not undefined, as === is used.)
So you can try setting your model variable to null.
If that doesn't work, I expect you may be out of luck as far as proper solutions go, and might need to re-render the whole directive. You can create a pretty simple directive to do that, similar to what's suggested in this answer: https://stackoverflow.com/a/22133080/624590

How to handle two inputs which depend on each other?

Let's say that I have to <select> lists:
<select valueLink={this.linkState('parent')}>...</select>
<select valueLink={this.linkState('child')}>...</select>
Child select depends on parent select (when parent is selected then child is filled with new options and its value is set to first option by default.
The problem is that in order to "reset" child select I would have to set component state in response to state-change event, which is highly discouraged AFAIK. So how to handle this situation?
If I understand your issue correctly, this may help.
JSFIDDLE
By changing what options the select has we automatically reset it when we change the first select. I've also made the second select completely dependent on the first select's state.
<select valueLink={this.linkState('select')}>
{this.renderOptions(Object.keys(this.selectOptions))}
</select>
<select>
{this.renderOptions(this.selectOptions[this.state.select])}
</select>
let me know if I misunderstood your issue.
Update / EDIT:
I think I understand your issue a bit more. In this case you have a complicated relationship with your two inputs, and can't rely on the 1:1 relationship that this.linkState() gives you.
In this case I added a custom onChange method to the first select and set the value and initial value of the second selection from that. Since the second selection isn't doing anything fancy we can use linkState on it just fine.
UPDATED FIDDLE
<select onChange={this.handleMainSelectChange}>
{this.renderOptions(Object.keys(this.selectOptions))}
</select>
<select valueLink={this.linkState('secondSelection')}>
{this.renderOptions(this.selectOptions[this.state.mainSelection])}
</select>
And the click handler
handleMainSelectChange: function (event) {
var value = event.target.value;
this.setState({
mainSelection: value,
secondSelection: this.selectOptions[value][0]
});

Resources