Angular JS - Select field not loading content when editing - angularjs

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

Related

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

two-way binding in directive, model from service non-assignable

I am getting the following error: "Expression '{0}' used with directive '{1}' is non-assignable!", as can be shown here: https://docs.angularjs.org/error/$compile/nonassign
Edit: Having moved the config object into the scope this part is resolved, however the models are still not bound as expected. http://plnkr.co/edit/AVs2IW75oWavpsPNDgnb?p=preview
Old plunker: http://plnkr.co/edit/AVs2IW75oWavpsPNDgnb?p=preview
(Try and edit a field and check the console)
I don't really understand the problem which is why that link can't help me to solve it. I am using a directive to bind data, and the data that is being "bound" is actually pointing to a service.
<multi-edit model="profileService.current" config="{
title: 'Edit profile description',
fields: [
{name: 'Title', model: profileService.current.title, input: true},
{name: 'Description', model: profileService.current.description, textarea: true}
]}">
CLick me
</multi-edit>
So I am trying to edit profileService.current.title for example, by using the ng-model config.fields[0].model. It can read the data correctly, but not write to it. What do I need to do in order to be able to write to the correct models?
UPDATED
You should use a scope model for "config".
Put this in your main controller:
$scope.config = {
title: 'Edit profile description',
fields: [{
name: 'Title',
model: 'title',
input: true
}, {
name: 'Description',
model: 'description',
textarea: true
}]
};
and then in your main HTML:
<multi-edit model="profileService.current" config="config">
CLick me
</multi-edit>
Then, in your directive HTML:
<li ng-repeat="(key, value) in config.fields">
<input ng-if="value.input" type="text" ng-model="model[config.fields[key].model]" />
<textarea ng-if="value.textarea" type="text" ng-model="model[config.fields[key].model]"></textarea>
</li>
See the updated plunker.

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

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

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