How to autocapitalize an input field?

How to autocapitalize the first character in an input field inside an AngularJS form element?

I saw the jQuery solution already, but believe this has to be done differently in AngularJS by using a directive.

Yes, you need to define a directive and define your own parser function:

myApp.directive('capitalizeFirst', function($parse) {
   return {
     require: 'ngModel',
     link: function(scope, element, attrs, modelCtrl) {
        var capitalize = function(inputValue) {
           if (inputValue === undefined) { inputValue = ''; }
           var capitalized = inputValue.charAt(0).toUpperCase() +
                             inputValue.substring(1);
           if(capitalized !== inputValue) {
              modelCtrl.$setViewValue(capitalized);
              modelCtrl.$render();
            }         
            return capitalized;
         }
         modelCtrl.$parsers.push(capitalize);
         capitalize($parse(attrs.ngModel)(scope)); // capitalize initial value
     }
   };
});

HTML:

<input type="text" ng-model="obj.name" capitalize-first>

Fiddle

Please remember that not everything needs an Angular solution. You see this a lot with the jQuery crowd; they like to use expensive jQuery functions to do things that are simpler or easier to do with pure javascript.

So while you might very well need a capitalize function and the above answers provide that, it's going to be a lot more efficient to just use the css rule "text-transform: capitalize"

<tr ng-repeat="(key, value) in item">
    <td style="text-transform: capitalize">{{key}}</td>
    <td>{{item}}</td>
</tr>

You can create a custom filter 'capitalize' and apply it to any string you want:

 <div ng-controller="MyCtrl">
     {{aString | capitalize}} !
</div>

JavaScript code for filter:

var app = angular.module('myApp',[]);

myApp.filter('capitalize', function() {
    return function(input, scope) {
        return input.substring(0,1).toUpperCase()+input.substring(1);
    }
});

Use the CSS :first-letter pseudo class.

You need to put everything lowercase and after apply the uppercase only to the first letter

p{
    text-transform: lowercase;
}
p:first-letter{
    text-transform: uppercase;
}

Here's an example: http://jsfiddle.net/AlexCode/xu24h/

I would prefer a filter and directive. This should work with cursor movement:

app.filter('capitalizeFirst', function () {
    return function (input, scope) {
        var text = input.substring(0, 1).toUpperCase() + input.substring(1).toLowerCase();
        return text;
    }
});

app.directive('capitalizeFirst', ['$filter', function ($filter) {
    return {
        require: 'ngModel',
        link: function (scope, element, attrs, controller) {
            controller.$parsers.push(function (value) {
                var transformedInput = $filter('capitalizeFirst')(value);
                if (transformedInput !== value) {
                    var el = element[0];
                    el.setSelectionRange(el.selectionStart, el.selectionEnd);
                    controller.$setViewValue(transformedInput);
                    controller.$render();
                }
                return transformedInput;
            });
        }
    };
}]);

Here is a fiddle

Modified his code to capitalize every first character of word. If you give 'john doe', output is 'John Doe'

myApp.directive('capitalizeFirst', function() {
   return {
     require: 'ngModel',
     link: function(scope, element, attrs, modelCtrl) {
        var capitalize = function(inputValue) {
           var capitalized = inputValue.split(' ').reduce(function(prevValue, word){
            return  prevValue + word.substring(0, 1).toUpperCase() + word.substring(1) + ' ';
        }, '');
           if(capitalized !== inputValue) {
              modelCtrl.$setViewValue(capitalized);
              modelCtrl.$render();
            }         
            return capitalized;
         }
         modelCtrl.$parsers.push(capitalize);
         capitalize(scope[attrs.ngModel]);  // capitalize initial value
     }
   };
});

To fix the cursor problem (from where Mark Rajcok's solution), you can store element[0].selectionStart at the beginning of your method, and then ensure to reset element[0].selectionStart and element[0].selectionEnd to the stored value before the return. This should capture your selection range in angular

Here's a codepen for a filter that capitalizes the first letter: http://codepen.io/WinterJoey/pen/sfFaK

angular.module('CustomFilter', []).
  filter('capitalize', function() {
    return function(input, all) {
      return (!!input) ? input.replace(/([^\W_]+[^\s-]*) */g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}) : '';
    }
  });

You can use the provided uppercase filter.

http://docs.angularjs.org/api/ng.filter:uppercase

Comment to Mark Rajcok solution: when using $setViewValue, you trigger the parsers and validators again. If you add a console.log statement at the beginning of your capitalize function, you'll see it printed twice.

I propose the following directive solution (where ngModel is optional):

.directive('capitalize', function() {
   return {
     restrict: 'A',
     require: '?ngModel',
     link: function(scope, element, attrs, ngModel) {
         var capitalize = function (inputValue) {
             return (inputValue || '').toUpperCase();
         }
         if(ngModel) {
             ngModel.$formatters.push(capitalize);
             ngModel._$setViewValue = ngModel.$setViewValue;
             ngModel.$setViewValue = function(val){
                 ngModel._$setViewValue(capitalize(val));
                 ngModel.$render();
             };
         }else {
             element.val(capitalize(element.val()));
             element.on("keypress keyup", function(){
                 scope.$evalAsync(function(){
                     element.val(capitalize(element.val()));
                 });
             });
         }
     }
   };
});

Building off Mark Rajcok's solution; It's important to consider that the directive evaluate only when the input field in engaged, otherwise you'll get error messages firing off until the input field has a 1st character. Easy fix with a few conditionals: A jsfiddle to go with that: https://jsfiddle.net/Ely_Liberov/Lze14z4g/2/

      .directive('capitalizeFirst', function(uppercaseFilter, $parse) {
      return {
        require: 'ngModel',
        link: function(scope, element, attrs, modelCtrl) {
            var capitalize = function(inputValue) {
              if (inputValue != null) {
              var capitalized = inputValue.charAt(0).toUpperCase() +
                inputValue.substring(1);
              if (capitalized !== inputValue) {
                 modelCtrl.$setViewValue(capitalized);
                 modelCtrl.$render();
              }
              return capitalized;
            }
          };
          var model = $parse(attrs.ngModel);
          modelCtrl.$parsers.push(capitalize);
          capitalize(model(scope));
        }
       };
    });

Further to the CSS-only answers, you could always use Twitter Bootstrap:

<td class="text-capitalize">

You could use pure css:

input { text-transform: capitalize; }