azangru
azangru

Reputation: 2738

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:

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

Answers (2)

Wayne Ellery
Wayne Ellery

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>

Plunkr

Upvotes: 3

bluetoft
bluetoft

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

Related Questions