Loading values From a Select Box into an Angular scope/model - angularjs

I'm pretty new to Angular. One of the impressions that I'm getting while reading through the documentation is that you should avoid directly accessing the DOM because Angular should be doing this for you. In other words, I should avoid using jQuery to do things.
I'm trying to figure out how to load the values in a select box into Angular's scope variable. For example, if my HTML template includes the following snippet:
<select>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
<option value="3">Option 3</option>
</select>
I'd like to be able to have a variable set in the controller that would look like this after the page is loaded:
$scope.selectvals = [ { value: "1", description: "Option 1" },
{ value: "2", description: "Option 2" },
{ value: "3", description: "Option 3" }
]
I could use JQuery to do this, but then I would be touching the DOM. I was wondering if Angular provides some sort alternative for accomplishing this.
I also know that I could send this info via an Ajax call and use ng-option to load the select, but I would like to save the overhead of an additional Ajax request to load this little information into the select box.

You can use ng-options to populate the list like such:
<div ng-app ng-init="options=[{ value: '1', description: 'Option 1' }, { value: '2', description: 'Option 2'}]">
<select ng-model="selectedOption" ng-options="o.description for o in options"></select>
</div>
You will need to set ng-model to capture the selected item.
fiddle

<select ng-model="myVal" ng-options="val.description for val in selectvals"></select>
You bind to the scoped proerty selectvals that you created and the syntax is as above. Here's the official page for Select

Related

Angular JS - Select field not loading content when editing

I have a select field in AngularJs inside a ng-repeat:
HTML:
<span ng-repeat="lang in vm.formState.languageList track by $index">
<select ng-model="lang" ng-options="lang.name for lang in vm.langs">
<option value="">- Please Choose -</option>
</select>
</span>
Controller:
this.langs = [
{name: "English", id: "en"},
{name: "German", id: "ge"},
{name: "Spanish", id: "sp"},
{name: "French", id: "fr"},
...
];
formState.languageList is an array containing each lang object select by user in creation form, e.g. formState.languageList = [{name: "English", id: "en"}, {name: "Spanish", id: "sp"}]
My problem is: when I'm editing the form, I want the form fields (input, checkboxes, selects...) filled with current information. Everything works fine, except for select field.
How can I get this select fields loaded when editing the form?
Thanks in advance.
that is because you are facing the famous dot problem.
You can confirm it by change the ng-model to use $parent
ng-model="$parent.lang"
why it is not working is because ng-repeat is isolate scope directive.
the better way to solve it is use controllerAs syntax

Angular default select option

I am having a problem getting my select to properly set the default option for my data. I am fetching data from a server through an Ajax call. I then want to be able to edit this data using a form. I want to point the select to use options set in a controller object but when you edit the select I want the model to point to the ajax data because that is what I write back to the server. As you can see in my plunkr each of the four items should have their select options filled in but instead all of the selects start empty.
In the official documentation for angular they say to do the following to set the default:
angular.module('defaultValueSelect', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.data = {
availableOptions: [
{id: '1', name: 'Option A'},
{id: '2', name: 'Option B'},
{id: '3', name: 'Option C'}
],
selectedOption: {id: '3', name: 'Option C'} //This sets the default value of the select in the ui
};
}]);
//Then in the HTML file:
<select name="mySelect" id="mySelect"
ng-options="option.name for option in data.availableOptions track by option.id"
ng-model="data.selectedOption"></select>
In my case the options aren't in the ajax data however, only the currently selected option. So I want to manage available options via a controller object but bind the select to the ajax data. Thanks.
https://plnkr.co/edit/Q16QLT?p=preview
You should define which property of "option" you want to bind to:
<select ng-options="option.value as option.text for option in options" ng-model="item.select"></select>
Working demo https://plnkr.co/edit/BezGaYjykfQrFQ9nZop2?p=preview
Change your select to this:
<select ng-options="option.text as option.text for option in options" ng-model="item.select"></select>
This will definately work:
Since your ng-model contains the full option object you need to bind it with the object in ng-options as well
<select name="mySelect" id="mySelect"
ng-options="option as option.name for option in data.availableOptions track by option.id"
ng-model="data.selectedOption"></select>

how to bind angular to a single option object's property instead of an ng-model array for select multiple dropdowns

I am trying to use an angular binding on a select multi-select without using a main array to hold the values (most examples I see bind straight to the select tags via ng-options and ng-model, but I can't use a simple array to store the data right now outside of the options, but need to store if option is selected within the options themselves).
Here is an example of using ng-selected to initially select values based on a property 'selected' on the choice:
http://jsfiddle.net/armyofda12mnkeys/aLkLqqL6/3/
I was hoping I could add an ng-model="choice.selected" to the above code on the option tag (but that won't work as ng-model isn't meant to be used on an option tag).
Whats the best way to bind to each individual choice object?
Maybe a $watch of some sort or manual change event would work?
Thanks for any ideas/fiddle
P.S. the reason why I'm doing this is the model this is for is usually setup for 'grid' questions that have like 10 checkboxes going horizontally across the screen, and each choice sets its selected property like normal for a checkbox... But in mobile layouts, I switch the 'grid view' to be a native multi-select dropdown, which looks nicer on mobile, but it has to use the same model which I can't figure out.
var myApp = angular.module('myApp',[]);
var myApp = angular.module('myApp',[]);
myApp.controller("MyCtrl", function ($scope) {
$scope.main_question =
{
qid: 'QS1',
question_type: 'dropdown',
text: 'What country you from? ',
dropdownAnswer: 'CA',
choices: [
{option_value: 'US', option_txt: 'United States', selected: false},
{option_value: 'CA', option_txt: 'Canada', selected: true},
{option_value: 'MX', option_txt: 'Mexico', selected: false},
{option_value: 'DE', option_txt: 'Germany', selected: true},
{option_value: 'NN', option_txt: 'None of the Above (exclusive, should unset other options)', selected: false}
]
};
});
select {
height: 10em;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<div>
{{main_question.qid}}. {{main_question.text}}<br/>
<select
name="{{main_question.qid}}"
id="{{main_question.qid}}"
multiple="multiple"
>
<option value="" id="{{main_question.qid}}_not_picked">--Please Choose--</option>
<option
ng-repeat="choice in main_question.choices"
id="{{main_question.qid}}_{{choice.option_value}}"
ng-value="{{choice.option_value}}"
ng-selected="choice.selected"
>{{choice.option_txt}}</option>
</select>
</div>
<br/>{{main_question.choices}}
</div>
</div>
You can to use ng-click to invert the selection:
<option
ng-repeat="choice in main_question.choices"
id="{{main_question.qid}}_{{choice.option_value}}"
ng-selected="choice.selected"
ng-click="choice.selected = ! choice.selected"
>{{choice.option_txt}}</option>
Take a look at jsbin

Move from final 1.3 rc to 1.3.0 - <select> option problems after <select> bug fixes made in the move

My application has this HTML:
<select id="contentTypeSelect"
ng-change="home.configChanged(true)"
ng-model="ctrl.configService.admin.contentTypeId"
ng-options="item.id as item.name for item in content"></select>
Here is the value of content:
var content =
[{"id":0,"name":"*"},
{"id":1,"name":"Menu"},
{"id":2,"name":"Service"},
{"id":3,"name":"Help"},
{"id":4,"name":"Product"},
{"id":5,"name":"Version"},
{"id":6,"name":"Exam"},
{"id":7,"name":"Track"}]
My problem is that it creates a select with a blank entry:
<select id="contentTypeSelect"
ng-change="home.configChanged(true)"
ng-model="ctrl.configService.admin.contentTypeId"
ng-options="item.id as item.name for item in content"
class="ng-pristine ng-untouched ng-valid">
<option value="? string: ?">
</option><option value="0" selected="selected">*</option>
<option value="1">Menu</option>
<option value="2">Service</option>
<option value="3">Help</option>
<option value="4">Product</option>
<option value="5">Version</option>
<option value="6">Exam</option>
<option value="7">Track</option>
</select>
Can someone help explain to me why this line is in the HTML:
<option value="? string: ?">
Here is how I am populating the select data:
self.content = results[2];
self.configService.admin.contentTypeId = self.content[0].id;
First I populate the data in self.content and then I set the modal to the id of the first element of that array.
Note this is only a problem with the production 1.3 release. I am not seeing this problem with that beta.
> #license AngularJS v1.3.0-beta.8 // This release is working for me
> #license AngularJS v1.3.0-rc.3 // This release is working for me
> #license AngularJS v1.3.0-rc.5 // This release is working for me
> #license AngularJS v1.3.0 // This release is failing for me
I assume now that this change is the result of the following change made between rc5 and the production release:
1.3.0 superluminal-nudge (2014-10-13)
Bug Fixes
select:
add basic track by and select as support (addfff3c, #6564)
manage select controller options correctly (2435e2b8, #9418)
I will look into this. Hopefully the bug fix did not introduce a new bug that I am facing. Certainly my code now appears to work in all versions prior to 1.3.0
Please note the order that my application works.
a) Open the HTML
b) Get the data for the select list (takes 5 seconds)
c) Populate ng-options
d) Populate ng-model
Could this be a problem related to the bug fix that was added just before the release of 1.3.0 to the options. My same code has been working for a year now and suddenly is giving me this problem ONLY with the latest 1.3.0 release.
This seems to be a known bug with v1.3.0 (see: https://github.com/angular/angular.js/issues/9714 and https://github.com/angular/angular.js/issues/9691).
The bug is in someway triggered by an async assignment of ngOptions model data and pre-selecting a value with a falsy identifier (e.g. '' or 0). It can be reproduced as follows:
(function (app, ng) {
'use strict';
app.controller('AppCtrl', ['$timeout', function($timeout) {
var vm = this;
$timeout(function () {
vm.content = [
{ id: 0, name: 'A' },
{ id: 1, name: 'B' },
{ id: 2, name: 'C' }
];
}, 1000);
}]);
}(angular.module('app', []), angular));
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.min.js"></script>
<div data-ng-app="app">
<!-- wrong behavior -->
<div data-ng-controller="AppCtrl as app1" data-ng-init="app1.selected = 0;">
<select
data-ng-model="app1.selected"
data-ng-options="item.id as (item.name + ' [' + item.id + ']') for item in app1.content"
size="4"
></select>
</div>
<!-- correct behavior -->
<div data-ng-controller="AppCtrl as app2" data-ng-init="app2.selected = 1;">
<select
data-ng-model="app2.selected"
data-ng-options="item.id as (item.name + ' [' + item.id + ']') for item in app2.content"
size="4"
></select>
</div>
</div>
This additional option results from no item beeing selected by default. If you set ctrl.configService.admin.contentTypeId to a valid ID from your list of items that one will be selected and you will no longer see this additional option with value ?
So this results from either no selection was defined or there is an error and the selected item can not be determined
Update:
I changed the AngularJS version to 1.3 and it still behaves as expected
Update2:
Eventually you should propagate the new value of self.configService.admin.contentTypeId by calling $scope.apply()?
Update3:
Added an async function for simulating getting data from service.
Without calling $apply() there is no way for Angular to know that any of the $scope values have changed since there are no events which can trigger an update. So you have to tell Angular that you changed some value. You can see this if you remove the $apply() call, then event the simple message text does not get updated.
Update4:
Changed setTimeout to $timeout since then $apply() is not required liks Yoshi explained.
Example:
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function ($scope, $timeout) {
$scope.status = 'loading...';
$scope.getData = function () {
$timeout(function () {
$scope.selectedItem = 0;
$scope.content =
[{ "id": 0, "name": "*" },
{ "id": 1, "name": "Menu" },
{ "id": 2, "name": "Service" },
{ "id": 3, "name": "Help" }]
$scope.status = 'Call done!';
}, 1000);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl" ng-init="getData()">
<label>Status: {{status}}</label><br/>
<select ng-model="selectedItem" ng-options="item.id as item.name for item in content"></select>
</div>
</div>

How to get Select2 tags initializing correctly with Angular UI when option groups are used?

I have been trying to get my angular ui select2 directive to initialize and have been unable to get it to work with option groups.
The Code:
function testCtrl1($scope)
{
$scope.selectedOptions = ['1'];
$scope.categories = [
{label: 'cat1', options: [{desc: 'one', value: 1}]},
{label: 'cat2', options: [{desc: 'two', value: 2}]}
];
}
The HTML:
<select multiple ui-select2 ng-model="selectedOptions" style="width: 300px">
<optgroup ng-repeat="category in categories" label="{{category.label}}">
<option ng-repeat="option in category.options" value="{{option.value}}">{{option.desc}} - {{option.value}}</option>
</optgroup>
</select>
The Fiddle:
I created the following jsfiddle.
While doing so I notice that it would initialize correctly if I included a second select2 directive that didn't include the option groups (weird). I notice some other odd behavior when including the second select2 but I am not too concerned about it since my goal is just to get testCtrl1 working.
Download latest angular-ui select2 and update line 24:
repeatOption = tElm.find( 'optgroup[ng-repeat], optgroup[data-ng-repeat], option[ng-repeat], option[data-ng-repeat]' );
Now its supports option groups.
Well i've gotten to the same obstacle and want to share my solution. Select2 was not watching the optgroup ng-repeat attribute. You have to add this to your angular ui select2 directive.
Change this:
repeatOption = tElm.find('option[ng-repeat], option[data-ng-repeat]');
To that:
repeatOption = tElm.find('optgroup[ng-repeat], optgroup[data-ng-repeat], option[ng-repeat], option[data-ng-repeat]');
Not sure if this is a clean solution but it works for me.
Github issue
select2 supports <optgroup> through hierarchical data, you can to pass-through a structured object as data instead of using ng-repeat, see
http://ivaynberg.github.io/select2/#data_array
Also search for "Example Hierarchical Data" in the page.
JS:
$scope.model = {
data: [
// both 'id' and 'text' are needed unless you write custom functions
{ text: 'cat1', children: [{id: 1, text: 'one'}] },
{ text: 'cat2', children: [{id: 2, text: 'two'}] }
]
];
HTML:
<input type="hidden" multiple ui-select2="model"
ng-model="selectedOptions" style="width: 300px">
selectedOptions will be an array of objects: [ {id: 1, text: 'one'} ].
For pass-through via the directive, see Angular UI's demo:
http://plnkr.co/edit/gist:4279651?p=preview
EDIT: update code and reference to site

Resources