How to update the ng-model when using ng-options in Angularjs? - javascript

I cant make my model to be updated when I select an option.
Here is my view:
<select data-ng-model="period" ng-options="item.value as item.text for item in periodOptions"></select>
And in my controller.js I have the following :
$scope.periodOptions = [
{ text: "This week", value: 'week' },
{ text:"This month", value: 'month '},
{ text:"This year", value: 'year' },
{ text:"All times", value: 'all-time '}
];
$scope.Search = function () {
return $http({
url: '/api/get',
method: 'GET',
params: {
period: $scope.period
}
}).then(function(response) {
console.log(response);
}, function(reason) {
alert(reason);
});
};
The $scope.period does not take the value of the option that is chosen from the User. I spent many hours on this and can't figure it out why is this happening.

In my case ng-model was not updating because my select is inside an element with ng-if.
<div class="editor-panel" ng-if="editorEnabled">
...
<select ng-options="item as item.description for item in items" ng-model="selectedItem"/>
...
</div>
ng-if creates another scope and ng-model refers to a variable in this child scope rather than the intended variable.
To fix the issue I changed ng-model="selectedItem" value to ng-model="$parent.selectedItem

There is a note in angularjs documentation for select.
"Note: ngModel compares by reference, not value. This is important when binding to an array of objects. See an example in this jsfiddle. "
Here is the fiddle of same solution as yours.
Below is a solution which should work (Notice a minor change to your existing code use ng-options="item as item.text ... instead of ng-options="item.value as item.text). Hope this helps!
var myCtrl = function($scope){
$scope.periodOptions = [
{ text: "This week", value: 'week' },
{ text:"This month", value: 'month '},
{ text:"This year", value: 'year' },
{ text:"All times", value: 'all-time '}
];
$scope.Search = function () {
alert('will call api with period: '+$scope.period.text);
/*
return $http({
url: '/api/get',
method: 'GET',
params: {
period: $scope.period
}
}).then(function(response) {
console.log(response);
}, function(reason) {
alert(reason);
});
*/
};
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-controller="myCtrl">
<select data-ng-model="period" ng-options="item as item.text for item in periodOptions" ng-change="updatePeriod()"></select>
<div>{{period}} </div>
<button ng-click='Search()' >Search</button>
</div>

try this
<div ng-controller="MyCtrl">
<select data-ng-model="period" ng-options="item.value as item.text for item in periodOptions"></select>
<span>period value=, {{period}}!</span>
</div>

The code for select and ngOptions is correct. However I assume that you want $scope.Search function to be called on every option change. In this case you need to set up ngChange handler:
<select ng-model="period"
ng-options="item.value as item.text for item in periodOptions"
ng-change="Search()">
</select>

Related

angularjs select depending on number of options in model

I currently have a select in an angular app :
http://jsfiddle.net/4qKyx/251/
And I'm trying to manage my select depending on the number of result.
HTML
<div ng-controller="MyCtrl">
<select ng-model="form.type" required="required" ng-options="option.value as option.name for option in typeOptions" >
</select>
</div>
JS
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.typeOptions = [
{ name: 'Feature', value: 'feature' },
{ name: 'Bug', value: 'bug' },
{ name: 'Enhancement', value: 'enhancement' }
];
if($scope.typeOptions.length == 1){
$scope.form = {type : $scope.typeOptions[0].value};
}else{
// first option set to "select an option" and null -> won't work with required
}
}
If I have only one element in my typeOptions, i want the only option to be pre-selected. Now if I have more than one element, I want an option saying "Select an option" but which can't be let selected in a required select. Thank you in advance for any help !
Can you try you controller code as like below,
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.form = {};
$scope.typeOptions = [
{ name: 'Feature', value: 'feature' },
{ name: 'Bug', value: 'bug' },
{ name: 'Enhancement', value: 'enhancement' }
];
$scope.form.type=($scope.typeOptions.length===1) ? $scope.typeOptions[0].value : '';
}
also updated your jsfiddler
The code you've provided on SO works.
Your issue is only on the fiddler with the line
<option style="display:none" value="">select a type</option>
if you want your "placeholder" inside the select, you can do it like that :
if($scope.typeOptions.length == 1){
$scope.form = {type : $scope.typeOptions[0].value};
}else{
$scope.typeOptions.unshift( { name: 'Select a value', value: '' });
}
you can add option element to your select to be like
<select ng-model="" required
ng-options="option.value for option in typeOptions">
<option value=''>- Please Choose -</option>
</select>
and just do the check in you controller if the options.length equals 1 then set the ng-model the good thing is the required validation still works.
here is jsfiddle
if you removed the comment it show select option

AngularJS + select2 - How to set initial value

I want to use Select2 in my AngularJS project, So I added an input like this :
<select class="find-neighborhood js-states form-control"
ng-model="regionIdentifier"
ng-init="">
</select>
Luckily , Whenever regionIdentifier is change, I find out. Actually I want to set initial value in my Select2. Here is my javascript code :
$(".find-neighborhood").select2({
dir: "rtl",
placeholder: "find neighborhood ...",
allowClear: true,
data: $scope.regions
});
My $scope.regions looks like :
[object,object,object]
Each object is like :
0 :Object
id:52623
regionSlug:yvuj
text:yvuj1
How to init value in my select2?
You should create a directive to make this work globally and fine. Here is a simple example which let you initialize a select2 set the default option values to your selection. You can find a working version on plnkr. While select2 depends on jQuery you may will look for an other lib to make it work. Some dev's preffer to have no jQuery included in AngularJS projects.
Controller
//option list
$scope.regions = {
'test1' : {
id: 1
},
'test2' : {
id: 2
},
'test3' : {
id: 3
},
'test4' : {
id: 4
},
'test5' : {
id: 5
}
};
//model & selected value setup
$scope.regionIdentifier = 3;
View
<select class="js-example-basic-single"
ng-model="regionIdentifier"
items="regions"
items-selected="regionIdentifier"
id="regionSelection"
select-two>
</select>
Directive
/**
* Simple select2 directive
*/
angular.module('app').directive('selectTwo', ['$timeout', function($timeout){
return {
restrict : 'EA',
transclude : true,
terminal: true,
templateUrl : 'views/directive/select2.html',
scope: {
items: "=",
itemsSelected: "="
},
link: function($scope, $element, $attrs, $controller){
//format options https://select2.github.io/select2/#documentation
function format(state) {
//init default state
var optionTemplate = state.text;
if (!state.id || state.id == 0) { //option group or no selection item
return optionTemplate;
}
return optionTemplate;
}
//init on load
$timeout(function(){
//if multiple options are possible, parse an comma seperated list into itemsSelected like 1,2,5,23,21
if (angular.isString($scope.itemsSelected) && $scope.itemsSelected.split(',').length > 1) {
$scope.itemsSelected = $scope.itemsSelected.split(',');
}
$($element[0]).select2({
formatResult: format,
formatSelection: format,
escapeMarkup: function(m) { return m; }
}).val($scope.itemsSelected == undefined ? [0]: [$scope.itemsSelected]).trigger("change");
});
}
};
}]);
Directive template views/directive/select2.html
<option ng-repeat="(name, item) in items track by $index"
value="{{ item.id }}">
{{ name }}
</option>

how to show dropdown box after selecting any one of checkbox created in loop angular js

I am new to angular js programming so please excuse me if my question is naive.
I am populating a list of checkboxes depending upon values inside a json object.
I am using ng-repeat to iterate through the list of keys & values received & display the check box. When each of the check box is clicked I am making a server call to get relevant data. The data I receive should be populated in a dropdown list only when it is clicked & the dropdown should disappear on un-click. I want to capture the dropdown selected option after the user selects it.
I am stuck as to how to get it.
My code for reference :
HTML :
<div class="container" ng-controller="OptionsController" >
<div ng-repeat="(key, value) in options" ng-if="value === 'text'">
<!-- {{key}} : {{value}}-->
<input type="checkbox" ng-click="getDistinct(key)"/>
<label>{{key}}
</label>
<div class="animate-show">
<select id="selector" ng-model="QueryFormData.Graph.selected">
<option ng-repeat="name in QueryFormData.Graph.options"
ng-value="name">{{name}}</option>
</select>
</div>
</div>
</div>
Controller code :
myApp.controller('OptionsController', ['$scope', '$http', '$location', 'datashare',
function($scope, $http, $location, datashare) {
//$scope.options = datashare.jsonData;
$scope.options = {
"_id": "571a0fcfaa6d92581ec99b2e",
"Name": "text",
"isstring": "text",
"value1": "number",
"value": "number",
"status": "text",
"ItantaTime": "time"
};
$scope.keyArr = [];
$scope.QueryFormData = {
Graph: {
options: [
'Line Graph'
],
selected: 'Line Graph'
},
displayValue: ''
};
$scope.getDistinct = function(key) {
if ($scope.keyArr.indexOf(key) == -1) {
$scope.keyArr.push(key);
var ServerAddr = "http://localhost:2000/getDistinct/" + key;
console.log("Server Addr :" + ServerAddr);
$http.get(ServerAddr, {
headers: {
'Content-Type': 'application/json'
}
})
.success(function(result) {
console.log(result);
})
.error(function(data, status) {
console.log(data)
});
}
console.log("changed : " + key);
};
}
]);
With current code I am seeing all the dropdowns at once. I want to show the dropdowns as a toggle functionality on check box selection.
Any help is highly appreciated.
First, you don't need ng-if. Use the built-in filter:
<div ng-repeat="(key, value) in options" ng-if="value === 'text'">
Can be
<div ng-repeat="(key, value) in options | filter: { value: 'text' }">
For your filtering problem, you can again use the filter in select elements to only get the dropdown values you want. Your JSON response must have a filterable property though... So, please post your JSON.
You use it like this:
<select ng-options="item.key as item.name for item in collection| filter:{ someProperty: true }">

Angular change default value of select from filter

I have a select box which is populated with some data from my controller. When an input value changes the contents of the select box should be filtered and a default value should be assigned based on the is default property of the data object.
Is there any way this can be done using angular directives or would it need to be done as a custom filter function doing something along the lines of
angular.forEach(vm.data,function(item){
if (vm.q == item.someId && item.isDefault) {
vm.result = item.value;
}
});
My html looks something like
<div ng-app="myApp" ng-controller="ctrl as vm">
<input type="text" ng-model="vm.q">
<select ng-options="item.value as item.description for item in vm.data | filter:{someId:vm.q}" ng-model="vm.result"></select>
</div>
and my controller looks like:
(function(){
angular.module('myApp',[]);
angular
.module('myApp')
.controller('ctrl',ctrl);
function ctrl()
{
var vm = this;
vm.data = [
{
someId: '1',
description: 'test1',
value: 100,
isDefault: true
},
{
someId: '2',
description: 'test2',
value: 200,
isDefault: false
},
{
someId: '3',
description: 'test3',
value: 100,
isDefault: true
},
];
}
})();
See my plunkr demo here: http://plnkr.co/edit/RDhQWQcHFMQJvwOyHI4r?p=preview
Desired behaviour:
1) Enter 1 into text box
2) List should be filtered to 2 items
3) Select box should pre-select item 1 based on property isDefault set to true
Thanks in advance
I'd suggest you include some 3rd party library, like lodash, into your project to make working with arrays/collections that much easier.
After that you could add ng-change directive for your input.
<input type="text" ng-model="vm.q" ng-change="vm.onChange(vm.q)">
And the actual onChange function in the controller
vm.onChange = function(id) {
var item = _.findWhere(vm.data, { someId: id, isDefault: true });
vm.result = item ? item.value : null;
};
And there you have it.

space is shown when selecting the dropsdown option - angularjs

I have created an application in AngularJS with a drop down with space in option using a filter. The application is working fine with the options in drop down with indentation space before the values but the problem is when a select an option which is having a space, the space is also shown in the view like as shown below
actually I want the indentation space within the drop-down options but only thing is that I don't want that space to be get displayed when selection shown above
can anyone please tell me some solution to prevent the space to display when selection
My code is as given below
JSFiddle
<select>
<option ng-repeat="(key, value) in headers">{{value | space}}
</option>
</select>
<select ng-model="selectedValue" ng-change="selVal = selectedValue.trim(); selectedValue=selVal">
<option ng-if="selVal">{{selVal}}</option>
<option ng-repeat="(key, value) in headers" ng-if="selVal != value.value">
{{value | space}}
</option>
</select>
This is as close as it gets without jquery, temporarily changing the view state of the option when it's chosen. If that doesn't satisfy you and you still want it to be shown indented when the dropdown menu is open, check out this question on how to detect the state of the select component and update the display function accordingly. Alternatively, you can create your own select directive and manage the details within that, but I doubt that's worth the trouble if you're not using it in many places.
var app = angular.module('myApp', []);
app.controller('ArrayController', function ($scope) {
$scope.headers = [{
value: 'value 1'
}, {
value: 'value 2',
mainId: 12
}, {
value: 'value 3'
}, {
value: 'value 4',
mainId: 14
}, {
value: 'value 5'
}, {
value: 'value 6',
mainId: 18
}];
$scope.chosen = $scope.headers[0].value;
$scope.display = function(header) {
var chosenObject = _.find($scope.headers, {value: $scope.chosen});
if (!_.isUndefined(header.mainId) && header !== chosenObject) {
return '\u00A0\u00A0' + header.value;
} else {
return header.value;
}
}
});
HTML here:
<div ng-app='myApp' ng-controller="ArrayController">
<br></br>
SELECT:
<select ng-model="chosen" ng-options="header.value as display(header) for header in headers">
</select>
</div>
There's yet another alternative with CSS and ng-class, fiddle here:
var app = angular.module('myApp', []);
app.controller('ArrayController', function ($scope) {
$scope.headers = [{
value: 'value 1'
}, {
value: 'value 2',
mainId: 12
}, {
value: 'value 3'
}, {
value: 'value 4',
mainId: 14
}, {
value: 'value 5'
}, {
value: 'value 6',
mainId: 18
}];
$scope.chosen = $scope.headers[0].value;
$scope.isIndented = function(header) {
var chosenObject = _.find($scope.headers, {value: header});
return !_.isUndefined(chosenObject.mainId);
};
});
app.filter('space', function() {
return function(text) {
if(_.isUndefined(text.mainId))
{
console.log('entered mainId');
return text.value;
}
else
{
console.log('entered');
return '\u00A0\u00A0' + text.value;
}
};
});
HTML:
<div ng-app='myApp' ng-controller="ArrayController">
<br></br>
SELECT:
<select ng-model="chosen" ng-options="header.value as (header | space) for header in headers" ng-class="{'indented-value': isIndented(chosen)}">
</select>
</div>
CSS:
.indented-value {
text-indent: -9px;
}
First off, this was a great question. I've unfortunately spent way too much time trying to come up with a solution to this. I've tried everything from CSS, to using ngModelController $formatters, to the solution (which isn't optimal as you'll see) I've posted below. Note, I do not think my solution deserves to be selected as the answer. It just "sorta" works, but like other solutions, it has a fatal flaw.
However, since your question was:
can anyone please tell me some solution to prevent the space to
display when selection
My official answer is:
No
There is no cross-browser way to get this working. No amount of CSS, jQuery, or Angular magic will make this work. While it may be disappointing, I think that is going to be the only correct answer to your question.
No one is going to be able to give you a solution that prevents the space from being displayed in the select box while maintaining it in the options that works reliably across browsers. Chrome and Firefox allow some amount of styling of elements in the select, options, and optgroup family, but nothing is consistent and works everywhere.
My best run at it is in this Plunk
It uses the fact that optgroup will do indentations for you, but it comes with terrible differences in how different browsers handle it. With some you can style away the problem, but others do not work (and never will). I'm posting it so maybe someone will be inspired and figure out a way to prove me wrong.
<body ng-app="app">
<div ng-app='myApp' ng-controller="ArrayController">
<div>{{selectedValue}}</div>
SELECT:
<select ng-model="selectedValue" >
<option indented="item.mainId" ng-repeat="item in headers">{{item.value}}</option>
</select>
</div>
</body>
(function() {
var app = angular.module('app', []);
app.controller('ArrayController', function($scope, $timeout) {
$scope.headers = [{
value: 'value 1'
}, {
value: 'value 2',
mainId: 12
}, {
value: 'value 3'
}, {
value: 'value 4',
mainId: 14
}, {
value: 'value 5'
}, {
value: 'value 6',
mainId: 18
}];
});
app.directive('indented', function($parse) {
return {
link:function(scope, element, attr){
if($parse(attr.indented)(scope)) {
var opt = angular.element('<optgroup></optgroup>');
element.after(opt).detach();
opt.append(element);
}
}
};
});
})();
If you opened the question up and allowed the implementation of a directive that mimicked the behavior of select but was instead built with li elements, then this would be trivial. But you simply can't do it with select.
Given your code, you can add one helper directive, to remove space in link function, once your option got selected.
As an example, add an id to your select, and directive
<select id="mySelect" option-without-space>
<option ng-repeat="(key, value) in headers">{{value | space}}
</option>
</select>
And directive might look like,
app.directive('optionWithoutSpace', () => {
return {
restrict: 'A',
link: function(scope, elem, attributes) {
var selectedOptionWithoutSpace = function () {
var selectedOption = $('#mySelect option:selected');
var optionText = selectedOption.text();
selectedOption.text(optionText.trim())
return false;
};
$(elem).on('change', selectedOptionWithoutSpace);
}
}
})
This is with a little help of jQuery, but I assume it is not a big problem.
Here is a fiddle.
Try this...
Change select box html following
<select ng-model="selectedOption" ng-options="item.value for item in headers"></select>
var app = angular.module('myApp', []);
app.controller('ArrayController', function ($scope) {
$scope.headers = [{
value: 'value 1'
}, {
value:'value 2',
mainId: 12
}, {
value: 'value 3'
}, {
value: 'value 4',
mainId: 14
}, {
value: 'value 5'
}, {
value: 'value 6',
mainId: 18
}];
$scope.selectedOption = $scope.headers[0]; //Add this line
});
app.filter('space', function() {
return function(text) {
if(_.isUndefined(text.mainId))
{
console.log('entered mainId');
return text.value;
}
else
{
console.log('entered');
return '\u00A0\u00A0' + text.value;
}
};
});

Categories

Resources