The boolean value assigned to the model doesn't pre-select the corresponding option - shows first an empty option instead:
Select:
<select data-ng-model="scriptData.privacy" data-ng-options="privacyOption.value as privacyOption.label for privacyOption in privacyOptionsSelect track by privacyOption.value"></select>
Options in the controller:
$scope.privacyOptionsSelect=[
{
label:'Registered users only can view this',
value: false
},
{
label:'Anyone with the link can view this',
value: true
}
];
scriptData.privacy is set to false.
You should be careful when using the ngOptions expression with the format:
select as label for value in array
together with track by. This is because track by is applied to the value assigned to your ngModel, so if your selection is in the form privacyOption.value, the track by expression is actually applied to the value. This is the reason it doesn't successfully select the initial value.
To fix this you have two options. You can either just skip track by. This would work:
<select data-ng-model="scriptData.privacy"
data-ng-options="privacyOption.value as privacyOption.label for privacyOption
in privacyOptionsSelect"></select>
Or you could change the select as-expression to select the entire privacyOption-object. This would work as well (note the ngModel-directive changed as well):
<select data-ng-model="scriptData"
data-ng-options="privacyOption as privacyOption.label for privacyOption
in privacyOptionsSelect track by privacyOption.value"></select>
For a full (and probably better) explanation, I recommend the ngOptions documentation.
try ng-repeat instead of ng-options by applying the ng-repeat to option elements inside the select.
Related
I have a select tag to which I am applying angular chosen.
This is my select tag
<select name="rname" id="rname" ng-model="rname" ng-init="rname='CustomReport'"
ng-options="key as value for (key , value) in reportsValuesOptions track by key" chosen>
<option value="">---Select---</option>
</select>
The above select tag is getting populated from below object
$scope.reportsValuesOptions = {'Cash Position Report':'Cash Position Report','Detail Report':'Detail Report','Reconciliation Report':'Reconciliation Report','Summary Report':'Summary Report','Sweep Report':'Sweep Report','FCCS/FBPS Detail Report':'FCCS/FBPS Detail Report','CustomReport':'Custom Report Name'};
The object is a pair of values and options for select tag where the key is options tags value and the value is the option tag text
Now I want to set the default value of the select tag to 'CustomReport' as its option value and 'Custom Report Name' as its option text from the above object, using ng-init.
I tried doing ng-init="rname='CustomReport'", but it doesn't work
How to set its value from object's key value pair?
FULL EXAMPLE
The problem with your solution is since you are giving an object and AngularJS is mostly designed for arrays it causes AngularJS not to be able to track them properly. You probably wanted to write a shorter object for reportsValueOptions but it should be an array of objects which has a form similar to the following:
[
{label: 'First Label', value:'first-option'},
{label: 'Second Label', value:'second-option'}
]
Here is the modified version of your jsfiddle with modified object that also shows which one is selected.
You can also learn more about problems with objects here: https://docs.angularjs.org/api/ng/directive/ngOptions#complex-models-objects-or-collections-
You can simply use ng-init like this
<select ng-init="somethingHere = options[0]"
ng-model="somethingHere"
ng-options="option.name for option in options">
</select>
I have a select element with an ng-model and ng-options on it. ng-options makes the possible selections dynamic however I have noticed that when ng-options updates the options ng-model is not also getting updated. For example if the select element has the value of "foo" selected then the ng-options model is updated and "foo" is no longer an option the selector updates to blank but ng-model still shows "foo" as its value. I would expect that ng-model would update as well to equal null. The only thing I can think of is to add a watch on items but that seems kind of lame. What is the best way to get ng-model to stay in sync with the select element in this scenario?
<div ng-controller="MyCtrl">
<p>Selected Item: {{foo}}</p>
<p>
<label>option</label>
<select ng-model="foo" ng-options="item.val as item.label for item in items">
<option value="">Select Something</option>
</select>
</p>
<button ng-click="remove()">Remove Second Item Option</button>
<p>{{items}}</p>
</div>
Here is the jsfiddle to illustrate the issue. http://jsfiddle.net/dberringer/m2rm8Lh6/2/
Note: I'm aware I could manually update the foo value with the delete method. This method is just to illustrate the issue.
Thanks for your feedback.
Update: I fixed a typo where referred to ng-options as ng-select.
change the button like
<button ng-click="remove(2)">Remove Second Item Option</button>
change the remove function
$scope.remove = function(removeIndex) {
if($scope.foo == removeIndex) {
$scope.foo = null;
}
$scope.items.splice(removeIndex-1,1);
};
here is the Demo Fiddle
Reason is,
ng-change is not going to trigger when,
if the model is changed programmatically and not by a change to the input value, check the Doc here
so u are not changing the select value by changing the select box instead do it using a button (programmatically) so angular will not trigger the change event on the select element and then angular doesn't know model is changed ,this might be the reason.
then what u need to do is change model value manually as $scope.foo = null;
I think angular didn't check that, once the ngOptions value changes, angular didn't do a check to see if the ngModel is exists in ngOptions.
angular.js
line 21371:
self.databound = $attrs.ngModel;
line 21828 - 21840:
return function (scope, element, attr) {
var selectCtrlName = '$selectController',
parent = element.parent(),
selectCtrl = parent.data(selectCtrlName) ||
parent.parent().data(selectCtrlName); // in case we are in optgroup
if (selectCtrl && selectCtrl.databound) {
// For some reason Opera defaults to true and if not overridden this messes up the repeater.
// We don't want the view to drive the initialization of the model anyway.
element.prop('selected', false);
} else {
selectCtrl = nullSelectCtrl;
}
You can see above code checks which option should be selected when generated the options, but i can't find a reverse check when ngOptions got updated.
My html :
<select ng-controller="category" ng-model="selectedTestAccount" ng-options="c.category for c in categories track by c.categoryID" ></select>
<select ng-controller="subcatgory" ng-model="selectedTestAccount1" ng-options="c.subcategory for c in subcategories track by c.subcategoryID"></select>
My json will look like:
json1:
category: "Restaurants"categoryID: "1"
json2:
category: "Restaurants"categoryID: "1"subcategory: "European"subcategoryID: "1"
category: "Restaurants"categoryID: "1"subcategory: "Food Carts"subcategoryID: "17"
i want two dropdowns to be created. One for first json which will display categories.
on selecting the first category i want subcategories to be listed from second json. How to make first dropdown as mandatory.
Can anyone helpme with this
So I have created you a plnker
The key is the $watch which looks at the selected value (ng-model) of the first list then changes the values for the second list based on that new value.
$scope.$watch('selectedCategory', function(newValue) {
for (var i = 0; i < $scope.subCategories.length; i++){
if ($scope.subCategories[i].name === newValue){
$scope.selectedSubCategoryValues = $scope.subCategories[i].values;
}
}
});
You just need to:
add the required attribute on the first select
put an empty <option></option> inside the select (otherwise the select has already a default option which satisfy the requirement)
Here's the example:
http://jsfiddle.net/n5568q6o/1/
You can use a watch to watch the first object. If that changes change the array for the second one.
This will change the options according to the options you want for that.
I have this HTML
<select data-bind="value: $data.id">
<optgroup label="Regions" data-bind="foreach: countries.regions.names">
<option data-bind="html: $data.name, value: $data.value"></option>
</optgroup>
<optgroup label="Countries" data-bind="foreach: shipping.allCountries">
<option data-bind="html: $data.name, value: $data.code"></option>
</optgroup>
</select>
With this javascript which is being prefilled with an ID in either of the 2 optgroups. The ID is always present!
this.id = ko.observable(data.id);
But after the select is built by KnockOut, the value of this.id() is empty, and will return undefined. When I subscribe to the field, it gives me a notification it is being updated with nothing.
My current (dirty) fix:
setTimeout(function(){
self.id(data.id);
}, 500);
This works, but of course is not recommended.
Also, after selecting another element in the select and returning to the original value, it is fine too.
How do I fix this problem?
note: the correct element is selected.
The reason this fails is because the value of the <select> element is bound before its contents are bound using foreach and that the value binding will reset the model value to whatever is currently selected in the element if the model value can't itself be selected.
Example of problem: http://jsfiddle.net/mbest/8r6KY/
There are two solutions to this.
1. Prevent model value from being reset
One solution is to prevent the value binding from resetting the model value using a new binding option available in Knockout 3.1 (currently in Beta), valueAllowUnset.
<select data-bind="value: $data.id, valueAllowUnset: true">
Example: http://jsfiddle.net/mbest/D6dR2/
2. Binding contents before value
The second solution is to get the <option> elements in place before the value is bound. This can be done with a custom binding on the element that binds the contents early.
<select data-bind="bindInner, value: $data.id">
Binding:
ko.bindingHandlers.bindInner = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
ko.applyBindingsToDescendants(bindingContext, element);
return { controlsDescendantBindings: true };
}
};
Example: http://jsfiddle.net/mbest/ETFsa/
Recommendation
The first option uses a built-in solution, but does have a downside that the UI selection happens using setTimeout (within the value binding). Thus you could have a visible change in the selection as the view is initialized. The second option is, I think, the better one, although you could, of course, use both of these together to doubly fix the problem.
Make sure that your countries.regions.names is actually pointing to the correct place. If those options don't exist then the values won't exist.
I'm new to Ember.js and I'm trying to figure out how Select views bind their selection to the controller. I have this template:
{{view Ember.Select
contentBinding="content"
selectionBinding="selectedCompany"
optionLabelPath="content.name"}}
{{view Ember.Select
contentBinding="selectedCompany.employees"
selectionBinding="selectedEmployee"
optionLabelPath="content.name"}}
Employee: {{selectedEmployee.name}}
Age: {{selectedEmployee.age}}
I find that the second select does update when selectedCompany changes, but I can't reference the values of name or age in selectedEmployee until I change the second select's value to a different value physically.
How do I make it so that the selectedEmployee is set when the first select changes, such that I can use it's value?
For better clarity, I have my working code here.
Changing content of second selectbox does not actualy change its selection. You have to do it manually, for example by adding following method to controller
onChangeCompany : function() {
if (!this.get('selectedCompany.employees').contains(this.get('selectedEmployee'))) {
this.set('selectedEmployee', this.get('selectedCompany.employees').objectAt(0));
}
}.observes('selectedCompany')
It stil needs some non-null and array-range checking, but does the job - if you select an employee and then change company, employee will change as well.