@@ -1855,7 +1855,15 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
18551855 } ;
18561856
18571857 this . $$writeModelToScope = function ( ) {
1858- ngModelSet ( $scope , ctrl . $modelValue ) ;
1858+ var getterSetter ;
1859+
1860+ if ( ctrl . $options && ctrl . $options . getterSetter &&
1861+ isFunction ( getterSetter = ngModelGet ( $scope ) ) ) {
1862+
1863+ getterSetter ( ctrl . $modelValue ) ;
1864+ } else {
1865+ ngModelSet ( $scope , ctrl . $modelValue ) ;
1866+ }
18591867 forEach ( ctrl . $viewChangeListeners , function ( listener ) {
18601868 try {
18611869 listener ( ) ;
@@ -1930,6 +1938,10 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
19301938 $scope . $watch ( function ngModelWatch ( ) {
19311939 var modelValue = ngModelGet ( $scope ) ;
19321940
1941+ if ( ctrl . $options && ctrl . $options . getterSetter && isFunction ( modelValue ) ) {
1942+ modelValue = modelValue ( ) ;
1943+ }
1944+
19331945 // if scope model value and ngModel value are out of sync
19341946 if ( ctrl . $modelValue !== modelValue &&
19351947 ( isUndefined ( ctrl . $$invalidModelValue ) || ctrl . $$invalidModelValue != modelValue ) ) {
@@ -2062,6 +2074,55 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
20622074 </form>
20632075 </file>
20642076 * </example>
2077+ *
2078+ * ## Binding to a getter/setter
2079+ *
2080+ * Sometimes it's helpful to bind `ngModel` to a getter/setter function. A getter/setter is a
2081+ * function that returns a representation of the model when called with zero arguments, and sets
2082+ * the internal state of a model when called with an argument. It's sometimes useful to use this
2083+ * for models that have an internal representation that's different than what the model exposes
2084+ * to the view.
2085+ *
2086+ * <div class="alert alert-success">
2087+ * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
2088+ * frequently than other parts of your code.
2089+ * </div>
2090+ *
2091+ * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
2092+ * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
2093+ * a `<form>`, which will enable this behavior for all `<input>`s within it. See
2094+ * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
2095+ *
2096+ * The following example shows how to use `ngModel` with a getter/setter:
2097+ *
2098+ * @example
2099+ * <example name="ngModel-getter-setter" module="getterSetterExample">
2100+ <file name="index.html">
2101+ <div ng-controller="ExampleController">
2102+ <form name="userForm">
2103+ Name:
2104+ <input type="text" name="userName"
2105+ ng-model="user.name"
2106+ ng-model-options="{ getterSetter: true }" />
2107+ </form>
2108+ <pre>user.name = <span ng-bind="user.name()"></span></pre>
2109+ </div>
2110+ </file>
2111+ <file name="app.js">
2112+ angular.module('getterSetterExample', [])
2113+ .controller('ExampleController', ['$scope', function($scope) {
2114+ var _name = 'Brian';
2115+ $scope.user = {
2116+ name: function (newName) {
2117+ if (angular.isDefined(newName)) {
2118+ _name = newName;
2119+ }
2120+ return _name;
2121+ }
2122+ };
2123+ }]);
2124+ </file>
2125+ * </example>
20652126 */
20662127var ngModelDirective = function ( ) {
20672128 return {
@@ -2459,6 +2520,8 @@ var ngValueDirective = function() {
24592520 * value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
24602521 * custom value for each event. For example:
24612522 * `ngModelOptions="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }"`
2523+ * - `getterSetter`: boolean value which determines whether or not to treat functions bound to
2524+ `ngModel` as getters/setters.
24622525 *
24632526 * @example
24642527
@@ -2541,6 +2604,33 @@ var ngValueDirective = function() {
25412604 }]);
25422605 </file>
25432606 </example>
2607+
2608+ This one shows how to bind to getter/setters:
2609+
2610+ <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
2611+ <file name="index.html">
2612+ <div ng-controller="ExampleController">
2613+ <form name="userForm">
2614+ Name:
2615+ <input type="text" name="userName"
2616+ ng-model="user.name"
2617+ ng-model-options="{ getterSetter: true }" />
2618+ </form>
2619+ <pre>user.name = <span ng-bind="user.name()"></span></pre>
2620+ </div>
2621+ </file>
2622+ <file name="app.js">
2623+ angular.module('getterSetterExample', [])
2624+ .controller('ExampleController', ['$scope', function($scope) {
2625+ var _name = 'Brian';
2626+ $scope.user = {
2627+ name: function (newName) {
2628+ return angular.isDefined(newName) ? (_name = newName) : _name;
2629+ }
2630+ };
2631+ }]);
2632+ </file>
2633+ </example>
25442634 */
25452635var ngModelOptionsDirective = function ( ) {
25462636 return {
0 commit comments