Radio button and custom values in Angular JS [duplicate] - angularjs

Using AngularJS, I would like to create a list of options with radio buttons, the last of which has an empty text field labeled 'Other' for inputing an option that is not in the list. Here's a demonstration of what I have in mind that I bootstrapped in CodePen. Since Stack Overflow insists on including CodePen code in this message, here it is:
js:
angular.module('choices', [])
.controller("MainCtrl", ['$scope', function($scope) {
$scope.color = '';
$scope.colors = [
"Red",
"Green",
"Blue",
"Other"
];
$scope.changeColor = function(){
$scope.color = "Red"
};
}]);
html:
<html>
<head>
<body ng-app="choices" ng-controller="MainCtrl">
<div ng-repeat="color in colors">
<input type="radio" ng-model="$parent.color" ng-value="color" id="{{color}}" name="color">
<label>
{{color}}
</label>
<input type="text" ng-model="$parent.color" ng-show="color=='Other'">
</div>
<p></p>
The chosen color is <strong>{{color}}</strong>
<p></p>
<button ng-click="changeColor()">Change color</button>
</body>
</html>
Here is what I want this demo app to do:
When I choose any option except for Other, the text field should remain blank;
If I place cursor in the text field, the option Other should be selected
Once I start typing in the text field, the option Other should remain selected
If I change the model that registers the options (in the demo app achieved by clicking the Change color button), the corresponding radio button should be selected.
I achieved most of that functionality by using three models (one for color, one for keeping track of radio buttons and one for the Other field) and three watchers, but the resultant app seems brittle and fails some of the tests. Could you please suggest a better way for creating such a selector in Angular using as few models and watchers as possible?
(My question is somewhat similar to this SO question, but I hope is different enough not to be considered a duplicate.)

Add a separate scope property for the other text:
$scope.other = '';
Add a colorChanged() method which will be called when the color is changed. This will set the other text to empty if color is not 'Other':
$scope.colorChanged = function () {
if ($scope.color != 'Other') {
$scope.other = '';
}
};
This will also need to be called from changeColor(). I ended up changing changeColor to allow the color to be passed in. It otherwise defaults to red:
$scope.changeColor = function(color){
$scope.color = color || "Red";
$scope.colorChanged();
};
Add ng-change="colorChanged()" to radio button:
<input type="radio" ng-model="$parent.color" ng-value="color" id="{{color}}" name="color" ng-change="colorChanged()">
Change the textbox to use other as the model. Use ng-focus to detect when textbox is focused and then set color to 'Other'. Doing this will select the radio button.
<input type="text" ng-model="$parent.other" ng-show="color=='Other'" ng-focus="$parent.color = 'Other'"/>
Update the display of the color to show the other text:
The chosen color is <strong>{{color}}<span ng-if="color === 'Other' && other != ''"> - {{other}}</span></strong>
Plunkr

I made some very small modifications to your pen HERE.
The short of it is, instead of having 'Other' as a value, i made it a blank option, with the input actually controlling the value.
$scope.colors = [
"Red",
"Green",
"Blue",
""
];
html:
<label >
{{color || 'Other'}}
</label>
<input type="text" ng-model="$parent.color" ng-show="color==''">
This allows the input to actually control the value of 'Other'...

Related

Reduce the number of model updates with a color picker

I use a standard HTML color picker in my application:
<input type="color" ng-model="vm.currentUser.color" />
If I click the button of that color picker and manually change the color, then the model is updated very often. Since I have a watch on vm.currentUser.color, the corresponding method is also invoked very often, and that's problematic.
Is there any way to set the model variable only when the OK button of the color picker is clicked?
You can use ng-change on that field as it triggers only after the color popup is closed and if a change occurs (no matter how many times you change the color inside the popup): http://plnkr.co/edit/AjDgoaUFky20vNCfu04O?p=preview
angular.module('app', [])
.controller('Ctrl', function($scope, $timeout) {
$scope.x = '#ff0000';
$scope.res = '';
$scope.a = function(x) {
console.log(x);
$scope.res = 'Color changed to ' + x;
$timeout(function(){$scope.res = ''}, 2000);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="Ctrl">
<input type="color" ng-model="x" ng-change="a(x)">
<p>{{res}}</p>
</div>
Since AngularJS 1.3.0-beta.6, there is a ngModelOptions directive, perfectly suited to your problem. It allows you to "tune how model updates are done", which is perfectly what you're looking for.
For instance, you can update the model only if the value doesn't change after a reasonable amount of time. I'll use a value of 500 milliseconds here in order to make the effect really apparent, but in practice, a lower one seems more appropriate.
<input
type="color"
ng-model="color"
ng-model-options="{debounce: 500}"
/>

How to set radio button in angularjs with Object

I have created radio buttons in angularjs using array of objects using ng-value and ng-model.
`
<div ng-controller="DemoController">
<div ng-repeat="detail in details">
<input type="radio" ng-model="$parent.selectedVal" ng-value="detail" name="test">
</div>
{{selectedVal}}
</div>
`
On selection of radio button model is populated with corresponding object value. But I am not sure how to initialize it using controller with object.
var app = angular.module('myApp', []);
app.controller("DemoController",DemoController);
function DemoController($scope) {
$scope.selectedVal={name:"Def",age:4} ;
$scope.details=[{name:'Abc',age:2},{name:'Xyz',age:3},{name:'Def',age:4}];
}
You should reference the selected value from the details array instead of creating a new instance:
$scope.details = [{ name:'Abc', age:2 }, { name:'Xyz', age:3 }, { name:'Def', age:4 }];
$scope.selectedVal = $scope.details[2];
This will select the last of the 3 radio buttons. Also if both details and selectedVal are defined within the same scope you should update your radio button as well, it's quite unclear why you referenced selectedVal from a $parentScope:
<input type="radio" ng-model="selectedVal" ng-value="detail" name="test" />
And here's the updated fiddle: https://jsfiddle.net/sb3krc8c/2/

Radio button checked by default when using ng-repeat

I have been wanting to have a radio button checked out of a list of radio buttons that I present in the screen using ng-repeat, but my code does not work. This is what I am doing:
<div class="clubRole" data-ng-if="club.checked">
<div data-ng-repeat="role in securityGroups.slice(0,1)">
<input type="radio" class="clubRole" data-ng-model="club.role" data-ng-value="role.securityGroupCode" checked="checked"> {{role.description}}
</div>
<div data-ng-repeat="role in securityGroups.slice(1,securityGroups.length+1)">
<input type="radio" class="clubRole" data-ng-model="club.role" data-ng-value="role.securityGroupCode"> {{role.description}}
</div>
</div>
The intention of the code is to get the first radio button checked, and the others unchecked. That code has a problem: it does not work. But at least it gives the idea of what I am trying to do: I want one of the radio buttons checked by default, no matter which one it is.
Radio button will be check if the value of the input attribute is equal to the value of modal applied on the radio button.
<div ng-repeat="val in ['a','b','c']">
<input
type="radio"
name="val"
data-ng-model="role"
data-ng-value="val"
ng-init="$index==0?(role=val):''"
/>
{{val}}
</div>
Checked="checked" will not work in angular context. You can either set the value of radio button explicitly in controller or you can manage it in the view itself as i did in the above example.But the modal should be equate according to the value attribute on the inmput element.
For example if modal is x on three radio button's and each radio button have different value like a,b and c. then x must be equal to any of the value to be checked.
Plunker
You don't need to worry about checked.
HTML:
<div ng-app="app">
<div ng-controller="mainController">
<label ng-repeat="option in options">
<input type="radio" ng-model="$parent.selected" ng-value="option"/>{{option}}
</label>
</div>
</div>
JavaScript:
var appModule = angular.module('app', []);
appModule.controller('mainController', function($scope) {
$scope.selected = 'red';
$scope.options = ['red', 'blue', 'yellow', 'green'];
});
Working fiddle here: https://jsfiddle.net/qnw8ogrk/1/
You don't need checked="checked", I think angular will take care of it itself if you set the model to one of the values. Something like:
club.role = securityGroups.slice(0,1)[0].securityGroupCode;
Also, the scope may trip you up here, the model may have to be $parent.club.role
if you use a primitive type in list, the answer of bm1729 is correct, but if you use objects in the list, then look this example: https://jsfiddle.net/9chd58mk/2/
the first part is bad, because the selected object is look like same with a list item, but it doesn't same by reference. the == operator is false in this case
$scope.selected = {c:'red'};
$scope.options = [{c:'red'}, {c:'blue'}, {c:'yellow'}, {c:'green'}];
but the second and third examples are use the list item reference, and the radio button checked. the == operator is true in this case
$scope.options3 = [{c:'red'}, {c:'blue'}, {c:'yellow'}, {c:'green'}];
$scope.selected3 = $scope.options3[0];
<md-radio-group ng-model="data.group3">
<md-radio-button value="{{o._id}}" class="md-primary" ng-repeat="o in lstDataRecord" ng-click="updTemplateId(o._id)">
<div flex-gt-sm="50" style="height: 150px; width: 250px;">
<img src="{{PageInfo_PATH}}{{o.imgUrl}}" />
{{o.displayName}}
</div>
</md-radio-button>
<md-radio-button value="active" class="md-primary" [checked]='true'> </md-radio-button>
</md-radio-group>

Radio buttons plus a text field in Angular.js

Using AngularJS, I would like to create a list of options with radio buttons, the last of which has an empty text field labeled 'Other' for inputing an option that is not in the list. Here's a demonstration of what I have in mind that I bootstrapped in CodePen. Since Stack Overflow insists on including CodePen code in this message, here it is:
js:
angular.module('choices', [])
.controller("MainCtrl", ['$scope', function($scope) {
$scope.color = '';
$scope.colors = [
"Red",
"Green",
"Blue",
"Other"
];
$scope.changeColor = function(){
$scope.color = "Red"
};
}]);
html:
<html>
<head>
<body ng-app="choices" ng-controller="MainCtrl">
<div ng-repeat="color in colors">
<input type="radio" ng-model="$parent.color" ng-value="color" id="{{color}}" name="color">
<label>
{{color}}
</label>
<input type="text" ng-model="$parent.color" ng-show="color=='Other'">
</div>
<p></p>
The chosen color is <strong>{{color}}</strong>
<p></p>
<button ng-click="changeColor()">Change color</button>
</body>
</html>
Here is what I want this demo app to do:
When I choose any option except for Other, the text field should remain blank;
If I place cursor in the text field, the option Other should be selected
Once I start typing in the text field, the option Other should remain selected
If I change the model that registers the options (in the demo app achieved by clicking the Change color button), the corresponding radio button should be selected.
I achieved most of that functionality by using three models (one for color, one for keeping track of radio buttons and one for the Other field) and three watchers, but the resultant app seems brittle and fails some of the tests. Could you please suggest a better way for creating such a selector in Angular using as few models and watchers as possible?
(My question is somewhat similar to this SO question, but I hope is different enough not to be considered a duplicate.)
Add a separate scope property for the other text:
$scope.other = '';
Add a colorChanged() method which will be called when the color is changed. This will set the other text to empty if color is not 'Other':
$scope.colorChanged = function () {
if ($scope.color != 'Other') {
$scope.other = '';
}
};
This will also need to be called from changeColor(). I ended up changing changeColor to allow the color to be passed in. It otherwise defaults to red:
$scope.changeColor = function(color){
$scope.color = color || "Red";
$scope.colorChanged();
};
Add ng-change="colorChanged()" to radio button:
<input type="radio" ng-model="$parent.color" ng-value="color" id="{{color}}" name="color" ng-change="colorChanged()">
Change the textbox to use other as the model. Use ng-focus to detect when textbox is focused and then set color to 'Other'. Doing this will select the radio button.
<input type="text" ng-model="$parent.other" ng-show="color=='Other'" ng-focus="$parent.color = 'Other'"/>
Update the display of the color to show the other text:
The chosen color is <strong>{{color}}<span ng-if="color === 'Other' && other != ''"> - {{other}}</span></strong>
Plunkr
I made some very small modifications to your pen HERE.
The short of it is, instead of having 'Other' as a value, i made it a blank option, with the input actually controlling the value.
$scope.colors = [
"Red",
"Green",
"Blue",
""
];
html:
<label >
{{color || 'Other'}}
</label>
<input type="text" ng-model="$parent.color" ng-show="color==''">
This allows the input to actually control the value of 'Other'...

My Angular Select2 dropdown needs to pass more values than just options' names on change event

I'm using Angular-Select2 and what I need is actually on change collect some more values than just what currently chosen options have as their names.
For example, if options Red, Blue, Yellow are selected, the current value is array of those values. What I want to do is to have displayed below the select box all those (in this example) colors that are chosen. It works so far - "colors" are showing and as I remove one from the select box (as tags, by clicking X sign) the bottom updates accordingly.
What I need to further accomplish is to send along other values, or at least one (id) so I can query my database. I know, I could include it before the actual name and then remove in my list to be able to manipulate it separately but then the id is also shown in the dropdown list and within selected options.
How to proceed? Is there anything that may be attached to options and sent and readable within the below area in which textual selected options' text is shown.
I'm wathching for changes like this:
$scope.$watch('selectDiseaseState', function(newVal){
$scope.listDiagnosis = newVal;
});
EDIT: If confused - this is multiselect dropdown.
EDIT:
The select2 markup:
<select id="mySel2" ng-model="selectDiseaseState" class="form-control" multiple="multiple" placeholder="Start typing a name of disease state...">
<optgroup ng-repeat="item in select" label="{{item.label}}">
<option ng-repeat="option in item.options">{{option.value}}</option>
</optgroup>
</select>
You need to bind your ng-model in the ng-options binding using array of objects instead of simple array. You can then watch for changes on the dropdown and the newvalue will be the object containing all properties.
HTML
<div ng-app='app' ng-controller='controller'>
<select ng-model='selectDiseaseState' ng-options='item as item.Color for item in selectOptions'>
</select>
</div>
Angular code:
var app= angular.module('app', [])
.controller('controller', function($scope){
$scope.selectOptions = [
{Id: 1, Color: 'Red'},
{Id: 2, Color: 'Blue'},
{Id: 3, Color: 'Green'},
{Id: 4, Color: 'Yellow'}
];
$scope.selectDiseaseState = {};
$scope.$watch('selectDiseaseState', function(newVal){
$scope.listDiagnosis = newVal;
alert('Id: '+ $scope.listDiagnosis.Id + ' and Color: '+ $scope.listDiagnosis.Color);
});
});
DEMO

Resources