Reputation: 2738
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:
Other
, the text field should remain blank;Other
should be selectedOther
should remain selectedChange 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.)
Upvotes: 4
Views: 5644
Reputation: 7958
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>
Upvotes: 3
Reputation: 5443
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'...
Upvotes: 0