Repository: angular/angular.js
File: src/ng/directive/ngModel.js (JavaScript)

Code before:
   * {@link ngModel.NgModelController#$modelValue $modelValue}
   *
   * The following actions are performed by this method:
   *
   * - the $modelValue is run through the {@link ngModel.NgModelController#$formatters $formatters}
   * and the result is set to the {@link ngModel.NgModelController#$viewValue $viewValue}
   * - the `ng-empty` or `ng-not-empty` class is set on the element
   * - if the $viewValue has changed
   *   - {@link ngModel.NgModelController#$render $render} is called on the control
   *   - the {@link ngModel.NgModelController#$validators $validators} are run and
   *   the validation status is set.
   *
   * This method is called by ngModel internally when the bound scope value changes.
   * Application developers usually do not have to call this function themselves.
   *
   * This function can be used when the $viewValue or the rendered DOM value of the control should
   * be updated after a user input.
   *
   * For example, consider a text input with an autocomplete list (for fruit, where the items are
   * objects with a name and an id.
   * A user enters `ap` and then selects `Apricot` from the list.
   * Based on this, the autocomplete widget will call $setViewValue({name: 'Apricot', id: 443}),
   * but the rendered value will still be `ap`.
   * The widget can then call ctrl.$processModelValue() to run the model -> view
   * pipeline again, which includes a formatter that converts the object into the string `Apricot`
   * which is set to the $viewValue and rendered in the DOM.
   *
   * @example
   * <example module="inputExample" name="ng-model-process">
     <file name="app.js">
      angular.module('inputExample', [])
        .directive('processModel', function() {
          return {
            require: 'ngModel',
            link: function(scope, element, attrs, ngModel) {

              ngModel.$formatters.push(function(value) {
                if (angular.isObject(value) && value.name) {
                  return value.name;
                }

                return value;
              });

              ngModel.$parsers.push(function(value) {
                if (angular.isString(value)) {
                  return scope.items.find(function(item) {
                    return item.name === value;
                  }) || value;
                }


Review comment (suggestion):
Consider avoiding two `which` clauses. E.g. something line:

>The widget can then call `ctrl.$processModelValue()` to run the model -> view pipeline, which will use a formatter to convert the object to the string `Apricot`, update the `$viewValue` and finally rendered it in the DOM.

Code after:
   * {@link ngModel.NgModelController#$modelValue $modelValue}.
   *
   * The following actions are performed by this method:
   *
   * - the `$modelValue` is run through the {@link ngModel.NgModelController#$formatters $formatters}
   * and the result is set to the {@link ngModel.NgModelController#$viewValue $viewValue}
   * - the `ng-empty` or `ng-not-empty` class is set on the element
   * - if the `$viewValue` has changed:
   *   - {@link ngModel.NgModelController#$render $render} is called on the control
   *   - the {@link ngModel.NgModelController#$validators $validators} are run and
   *   the validation status is set.
   *
   * This method is called by ngModel internally when the bound scope value changes.
   * Application developers usually do not have to call this function themselves.
   *
   * This function can be used when the `$viewValue` or the rendered DOM value are not correctly
   * formatted and the `$modelValue` must be run through the `$formatters` again.
   *
   * #### Example
   *
   * Consider a text input with an autocomplete list (for fruit), where the items are
   * objects with a name and an id.
   * A user enters `ap` and then selects `Apricot` from the list.
   * Based on this, the autocomplete widget will call `$setViewValue({name: 'Apricot', id: 443})`,
   * but the rendered value will still be `ap`.
   * The widget can then call `ctrl.$processModelValue()` to run the model -> view
   * pipeline again, which formats the object to the string `Apricot`,
   * then updates the `$viewValue`, and finally renders it in the DOM.
   *
   * <example module="inputExample" name="ng-model-process">
     <file name="index.html">
      <div ng-controller="inputController" style="display: flex;">
        <div style="margin-right: 30px;">
          Search Fruit:
          <basic-autocomplete items="items" on-select="selectedFruit = item"></basic-autocomplete>
        </div>
        <div>
          Model:<br>
          <pre>{{selectedFruit | json}}</pre>
        </div>
      </div>
     </file>
     <file name="app.js">
      angular.module('inputExample', [])
        .controller('inputController', function($scope) {
          $scope.items = [
            {name: 'Apricot', id: 443},
            {name: 'Clementine', id: 972},
            {name: 'Durian', id: 169},
            {name: 'Jackfruit', id: 982},
            {name: 'Strawberry', id: 863}