Select default option with ng-options using a flat array - angularjs

I'm generating <option>'s with ng-options using a flat array. The problem I'm having is selecting the default option element I already have defined. Seems to be a very simple task and there's tons and tons of similar questions using objects or array of objects, but everything I have found and tried for my situation does not work.
<div ng-app="MyApp">
<div ng-controller="MyCtrl">
<select ng-options="opt as opt for opt in testOpt" data-ng-model="resultOpt">
<option value="">Choose Category</option>
</select>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.8/angular.min.js"></script>
angular.module('MyApp', []).controller('MyCtrl', ['$scope', function ($scope) {
$scope.testOpt = [
'ID',
'Name',
'Email',
'Address'
];
$scope.resultOpt = '';
}]);
What I'm trying to do is select the "Choose Category" option by default. As plenty of others have already suggested in other questions, I have tried to use $scope.resultOpt = '' in my controller and even tried ng-init="resultOpt = ''", but does that not work at all. This works great for an array of objects, or objects but not with simple arrays. I also do not want to go outside of the AngularJS framework, I don't like mixing and matching vanilla and AngularJS code, things become messy.
I found an existing jsFiddle that is working for AngularJS 1.4.8, but at least for AngularJS 1.7.8, this is not working when used with a flat array. Not sure if it was functionality that was removed in later versions, or it's simply a bug.
Full example:
https://jsfiddle.net/v4uesg02/4/
How can I select the "Choose Category" option by default using a flat array without going outside of AngularJS framework?

How to select the hard-coded null option with ng-options and ng-model
To select the single hard-coded <option>, assign null to the model:
angular.module('MyApp', []).controller('MyCtrl', ['$scope', function ($scope) {
$scope.testOpt = [
'ID',
'Name',
'Email',
'Address'
];
̶$̶s̶c̶o̶p̶e̶.̶r̶e̶s̶u̶l̶t̶O̶p̶t̶ ̶=̶ ̶'̶'̶;̶
$scope.resultOpt = null;
}]);
From the Docs:
Optionally, a single hard-coded <option> element, with the value set to an empty string, can be nested into the <select> element. This element will then represent the null or "not selected" option.
For more information, see
AngularJS <select> Directive API Reference
The DEMO
angular.module('MyApp', [])
.controller('MyCtrl', ['$scope', function ($scope) {
$scope.testOpt = [
'ID',
'Name',
'Email',
'Address'
];
$scope.resultOpt = null;
}]);
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="MyApp" ng-controller="MyCtrl">
<select ng-options="opt as opt for opt in testOpt"
data-ng-model="resultOpt">
<option value="">Choose Category</option>
</select>
<br><br>
<button ng-click="resultOpt=null">Reset</button>
</body>

One thing i would like to add to #georgeawg's answer is to put disabled as an attribute to the option so that it is not reselect-able in the future
<option value="" disabled>Choose Category</option>

Related

ng-model isn't updating when selecting an option

I have a form with with option list
<form class="column-form">
<select id="classSelection" ng-change="classOptionChange()" ng-model="selectedClass" maxHeight="120">
<option selected value="">{{classOptions}}</option>
</select>
</form>
Sample class options is here
[{"id":"classR","text":" Color - Red"},{"id":"classG","text":"Color - Green"}, {"id":"classY","text":"Color - Yellow"}]
My directive is simple as I'm just trying to print out the value of my selected option. However, it's always null.
(function() {
appModule.directive('classDefault', [ '$translate', '$timeout', '$window', classService, function($translate, $timeout, $window, $document, classService) {
return {
restrict : 'E',
scope : {
.......
}
link : function(scope, element) {
scope.classOptionChange() = function() {
console.log(scope.selectedClass);
Any suggestions?
UPDATE - Thanks for all the suggestions below. Apparently, we are using this widget that supposed to render the option lists and then bind to the select tag but it is currently broken.
You need to bind the array to the select tag. One option to do so is to use the NgOptions directive.
Here's an working example
angular.module("app",[]).controller("ctrl", function($scope){
$scope.items = [{"id":"classR","text":" Color - Red"},{"id":"classG","text":"Color - Green"}, {"id":"classY","text":"Color - Yellow"}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<select ng-change="classOptionChange()"
ng-model="selectedClass"
maxHeight="120"
ng-options="item as item.text for item in items">
</select>
<h3>{{selectedClass}}</h3>
</div>
It seems like you are not properly rendering all options that have been passed down to your directive. Ideally you should loop over the classOptions collection using ng-repeat/ng-options directive and render the select tag filled option's. And then specify ng-value-"opt" on each of your option element. That will basically help you assign whole option object to selectedClass ng-model.
Template
<form class="column-form">
<select id="classSelection"
ng-change="classOptionChange()" ng-model="selectedClass"
maxHeight="120">
<option selected value="">Select option</option>
<option ng-value="opt" ng-repeat="opt in classOptions">{{opt.text}}</option>
</select>
</form>
Demo Plunker

AngularJS select option initialize

I have this select tag:
<select class="form-control" data-ng-model="contact.title" data-ng-options="title.title as title.title for title in titles track by title.title">
<option></option>
</select>
and when I will edit the title nothing is selected but contact.title is Mag.. Therefore Mag. should be selected. Does anyone know what I have to do in order that Mag. is selected?
From what I found tinkering around in a jsfiddle, the 'track by' was unnecessary.
Please try removing it.
<select class="form-control" data-ng-model="contact.title"
data-ng-options="title.title as title.title for title in titles">
<option></option>
</select>
Changing the 'track by' portion to $index or another value changes the selection. It's best to not use it if you are sure all titles will be unique.
Working code for me:
<select class="form-control" data-ng-model="contact" data-ng-options="title.title for title in titles track by title.title">
<option></option>
</select>
In controller:
$scope.titles = [{title: "abc"}, {title: "pqr"}, {title: "xyz"}];
$scope.contact = $scope.titles[0];
Try this.
Try this:
$scope.titles = [{title: "abc"}, {title: "pqr"}, {title: "xyz"}];
$scope.contact = {};
And:
<select name="repeatSelect" id="repeatSelect" ng-model="contact.title">
<option ng-repeat="title in titles" value="{{title.title}}">{{title.title}} </option>
</select>
Use the ng-init directive to have a default option in a select. You can use something like:
html:
<select ng-init="contact.title = titles[0]"
ng-model="contact.title"
ng-options="title.title for title in titles">
</select>
js:
$scope.titles = [{title: "Title A"}, {title: "Title B"}, {title: "Title C"}];
tl;dr
Set the initial value the model for contact in the controller, change the ng-model attribute of the select list to just contact and update the ng-options to data-ng-options="title as title.title for title in titles".
Selecting "Mag."
Does anyone know what I have to do in order that Mag. is selected?
In order to select Mag. (the first item in the list of titles, ensure that there is a property contact setup in the controller to the first element in the array of titles (i.e. $scope.contact = $scope.titles[0];). Also, change the ng-model attribute of the select from contact.title to contact.
ngOptions expression syntax
Also, review the syntax for comprehension_expression under the Arguments section of ngOptions.
The titles data sources is an array, so under array data sources, we have an expression like this format:
select as label for value in array
The value of select should not be the same as label. So update the ng-options attribute like this:
data-ng-options="title as title.title for title in titles track by title.title"
And as has already been mentioned, the track by clause is unnecessary. It would be useful if there was a different property we needed to account for (e.g. an integer named id). Thus the ng-options attribute can be simplified to:
data-ng-options="title as title.title for title in titles"
Example
See it demonstrated in the snippet below:
angular.module('app', [])
.controller('ctrl', function($scope) {
$scope.titles = [{
title: "Mag."
}, {
title: "Mag.(FH)"
}, {
title: "Mag. Dr."
}, {
title: "Dr."
}];
$scope.contact = $scope.titles[0];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<select class="form-control" data-ng-model="contact" data-ng-options="title as title.title for title in titles">
</select>
<div>Contact.title: <span ng-bind="contact.title"></span></div>
</div>
Avoid ngInit
It has been suggested that ng-init be used to set the initial value, however, there is a note about this on the documentation for ngInit:
This directive can be abused to add unnecessary amounts of logic into your templates. There are only a few appropriate uses of ngInit, such as for aliasing special properties of ngRepeat, as seen in the demo below; and for injecting data via server side scripting. Besides these few cases, you should use controllers rather than ngInit to initialize values on a scope.1
This is because (one of) the uses of controllers is to:
Set up the initial state of the $scope object.2
Business logic like that should not be added the template.

Angular ui-sref on dropdown not working

I have an angular app with routing. I have a dropdown select defined as follows:
<select class="form-control" id="transactiontype" ng-model="tt">
<option><a ui-sref="cash">Cash</a></option>
<option><a ui-sref="cheque">Cheque</a></option>
<option><a ui-sref="debitcard">Debit</a></option>
<option><a ui-sref="creditcard">Credit</a></option>
</select>
When i select one of the dropdowns, somehow it is not loading the view i am referencing. Where am i going wrong? I also tried this:
<option ui-sref="creditcard">Credit</option>
I'm pretty sure it's because the a tags won't work inside the select - option tags.
As per this SO question: using href link inside option tag
Try writing a function that will redirect the page and trigger it based on the select change or maybe your model change, whatever it best for your program.
something like:
<select class="form-control" id="transactiontype" ng-model="tt" ng-change="locationChangeFunction()">
...
</select>
Your controller might look like:
angular.module('myApp')
.controller('myController', ['$scope', '$state', function ($scope, $state){
$scope.locationChangeFunction = function(){
$state.go($scope.tt);
}
}]);
EDIT
Use a combination of both solutions (credit to Hieu TB):
<select class="form-control" id="transactiontype" ng-model="tt" ng-options="opt.value as opt.label for opt in options" ng-change="locationChangeFunction()"></select>
ng-change will wait for the model change, which will change the DOM, which will trigger the change, now you're not running a resource consuming $watch function
consider using ng-options instead:
myApp.controller('MainController', ['$scope', '$state', function($scope, $state) {
$scope.options = [
{ label: 'Cash', value: 'cash' },
{ label: 'Cheque', value: 'cheque' },
{ label: 'Debit', value: 'debit' },
{ label: 'Credit', value: 'credit' }
];
$scope.$watch('tt', function(value) {
if(value) {
$state.go(value);
}
});
}]);
HTML:
<div ng-controller="MainController">
<select class="form-control" id="transactiontype" ng-model="tt" ng-options="opt.value as opt.label for opt in options">
</select>
</div>
EDIT: Agree with what #Likwid_T said, I think ng-change is the best choice to detect the change in select tag. I just forgot about it at that moment. So please refer to his answer too. Good day.
My solution ended up just using a generic href, but using the old ng-router declaration with a '#/' prefix. For example: instead of using...
<select class="form-control" id="transactiontype" ng-model="tt">
<option><a ui-sref="cash">Cash</a></option>
<option><a ui-sref="cheque">Cheque</a></option>
<option><a ui-sref="debitcard">Debit</a></option>
<option><a ui-sref="creditcard">Credit</a></option>
</select>
Try using href with '#/' prefix like so...
<select class="form-control" id="transactiontype" ng-model="tt">
<option>Cash</option>
<option>Cheque</option>
<option>Debit</option>
<option>Credit</option>
</select>

Why does Angular add an empty <option> if the value exist in the provided options?

I have read on many occasions that Angular tends to add an empty option at the beginning of the select element if the value of the model does not exist among the offered options.
However, I have a model whose value is set to 0 from the start, and 0 is provided as one of the options in the select element as well, yet there is still one empty option above my own options. It disappears after the actual option whose value is 0 gets selected.
Why is this and how do I get rid of it?
A very simple example of the problem I am experiencing is displayed here: http://jsfiddle.net/yuvnz7wr/
The javascript code:
var app = angular.module('Module', []);
app.controller('Test', function ($scope) {
$scope.model = 0;
$scope.options = [{
id: 0,
name: 'Zero'
}, {
id: 1,
name: 'One'
}];
});
The HTML code:
<div ng-app="Module">
<div ng-controller="Test as test">{{model}}
<select ng-model="model">
<option ng-repeat="option in options" ng-value="option.id">{{option.name}}</option>
</select>
</div>
</div>
You better use ng-options and ng-init directives for <select> with angular:
<div ng-app="Module">
<div ng-controller="Test as test">{{model}}
<select ng-model="model" ng-init="model = options[0].id" ng-options="option.id as option.name for option in options"></select>
</div>
</div>

Angularjs ng-selected populate

I am trying to populate the currently selected item in angular js.
The currently selected item is that with the id in event.email.chases[0].id
and I am trying to match it to a select box populated from case.activeChases
This does what I want so far, which updates whenever the select box changes.
<select
class="form-control"
name="chase"
id="chase"
ng-model="customer.chase"
ng-change="addEmailToChase(customer.chase.id, event.email.id)"
ng-options="cor as cor.emails[0].subject for cor in case.activeChases">
<option value="">None</option>
</select>
I need to find the chase in activeChases with activeChases[x].id = event.email.chases[0].id, so the correct value is selected upon the page load.
Could I possibly do this all within a ng-selected attribute?
Something wrong with your model and your ng-options, the object should be the same if you want an "auto-selected"
without a jsfiddle it's hard to reproduce your situation but I tryed something like that
var app = angular.module('App', []);
app.controller('Ctrl', function($scope) {
$scope.case = {
activeChases: [{
emails: [{
subject: 'toto'
}]
}, {
emails: [{
subject: 'tata'
}]
}]
};
// set "default value"
$scope.customer = {
chase: $scope.case.activeChases[1]
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<section ng-app="App" ng-controller="Ctrl">
<select class="form-control" name="chase" id="chase" ng-model="customer.chase" ng-change="addEmailToChase(customer.chase.id, event.email.id)" ng-options="cor as cor.emails[0].subject for cor in case.activeChases">
<option value="">None</option>
</select>
</section>
So this was my answer:
<select
class="form-control"
name="chase"
id="chase"
ng-model="event.email.chases[0].id"
ng-change="addEmailToChase(event.email.chases[0].id, event.email.id)"
ng-options="cor.id[0] as cor.emails[0].subject for cor in case.activeChases">
</select>
I wanted the default value to be event.email.chases[0].id in the select, so I just set ng-model to that, and changed the first option to cor.id[0] to use id in index.
I chose a random name for ng-model which was customer.chase which made no sense. event represents an ajax loaded form element so its safe for me to do this in my scope.
Also worth noting that the id in cor.id[0] is actually in a size one array due to incorrect design in the app.

Resources