diff options
| -rw-r--r-- | src/AngularPublic.js | 3 | ||||
| -rw-r--r-- | src/directive/input.js | 26 | ||||
| -rw-r--r-- | src/service/compiler.js | 17 | ||||
| -rw-r--r-- | test/directive/inputSpec.js | 38 | ||||
| -rw-r--r-- | test/service/compilerSpec.js | 12 | 
5 files changed, 86 insertions, 10 deletions
| diff --git a/src/AngularPublic.js b/src/AngularPublic.js index c922c5e2..65ebe3f0 100644 --- a/src/AngularPublic.js +++ b/src/AngularPublic.js @@ -101,7 +101,8 @@ function publishExternalAPI(angular){              ngChange: ngChangeDirective,              ngModelInstant: ngModelInstantDirective,              required: requiredDirective, -            ngRequired: requiredDirective +            ngRequired: requiredDirective, +            ngValue: ngValueDirective          }).          directive(ngAttributeAliasDirectives).          directive(ngEventDirectives); diff --git a/src/directive/input.js b/src/directive/input.js index c9553e39..348c9f25 100644 --- a/src/directive/input.js +++ b/src/directive/input.js @@ -558,7 +558,7 @@ function radioInputType(scope, element, attr, ctrl) {    ctrl.$render = function() {      var value = attr.value; -    element[0].checked = isDefined(value) && (value == ctrl.$viewValue); +    element[0].checked = (value == ctrl.$viewValue);    };    attr.$observe('value', ctrl.$render); @@ -1168,3 +1168,27 @@ var ngListDirective = function() {      }    };  }; + + +var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/; + +var ngValueDirective = [function() { +  return { +    priority: 100, +    compile: function(tpl, attr) { +      if (CONSTANT_VALUE_REGEXP.test(attr.ngValue)) { +        return function(scope) { +          attr.$set('value', scope.$eval(attr.ngValue)); +        }; +      } else { +        attr.$observers.value = []; + +        return function(scope) { +          scope.$watch(attr.ngValue, function(value) { +            attr.$set('value', value, false); +          }); +        }; +      } +    } +  }; +}]; diff --git a/src/service/compiler.js b/src/service/compiler.js index 9e03f186..8ddf77ae 100644 --- a/src/service/compiler.js +++ b/src/service/compiler.js @@ -732,7 +732,7 @@ function $CompileProvider($provide) {            if (src[key]) {              value += (key === 'style' ? ';' : ' ') + src[key];            } -          dst.$set(key, value, srcAttr[key]); +          dst.$set(key, value, true, srcAttr[key]);          }        });        // copy the new attributes on the old attrs object @@ -937,9 +937,11 @@ function $CompileProvider($provide) {       * can share the attribute. This function properly handles boolean attributes.       * @param {string} key Normalized key. (ie ngAttribute)       * @param {string|boolean} value The value to set. If `null` attribute will be deleted. +     * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute. +     *     Defaults to true.       * @param {string=} attrName Optional none normalized name. Defaults to key.       */ -    function attrSetter(key, value, attrName) { +    function attrSetter(key, value, writeAttr, attrName) {        var booleanKey = isBooleanAttr(this.$element[0], key.toLowerCase());        if (booleanKey) { @@ -962,12 +964,15 @@ function $CompileProvider($provide) {          }        } -      if (value === null || value === undefined) { -        this.$element.removeAttr(attrName); -      } else { -        this.$element.attr(attrName, value); +      if (writeAttr !== false) { +        if (value === null || value === undefined) { +          this.$element.removeAttr(attrName); +        } else { +          this.$element.attr(attrName, value); +        }        } +        // fire observers        forEach(this.$observers[key], function(fn) {          try { diff --git a/test/directive/inputSpec.js b/test/directive/inputSpec.js index 0b848df1..8d0e44b3 100644 --- a/test/directive/inputSpec.js +++ b/test/directive/inputSpec.js @@ -1078,4 +1078,42 @@ describe('input', function() {        expect(scope.value).toBe('value3');      }));    }); + + +  describe('ng-value', function() { + +    it('should evaluate and set constant expressions', function() { +      compileInput('<input type="radio" ng-model="selected" ng-value="true">' + +                   '<input type="radio" ng-model="selected" ng-value="false">' + +                   '<input type="radio" ng-model="selected" ng-value="1">'); +      scope.$digest(); + +      browserTrigger(inputElm[0], 'click'); +      expect(scope.selected).toBe(true); + +      browserTrigger(inputElm[1], 'click'); +      expect(scope.selected).toBe(false); + +      browserTrigger(inputElm[2], 'click'); +      expect(scope.selected).toBe(1); +    }); + + +    it('should watch the expression', function() { +      compileInput('<input type="radio" ng-model="selected" ng-value="value">'); + +      scope.$apply(function() { +        scope.selected = scope.value = {some: 'object'}; +      }); +      expect(inputElm[0].checked).toBe(true); + +      scope.$apply(function() { +        scope.value = {some: 'other'}; +      }); +      expect(inputElm[0].checked).toBe(false); + +      browserTrigger(inputElm, 'click'); +      expect(scope.selected).toBe(scope.value); +    }); +  });  }); diff --git a/test/service/compilerSpec.js b/test/service/compilerSpec.js index d7ecdafc..698fc23e 100644 --- a/test/service/compilerSpec.js +++ b/test/service/compilerSpec.js @@ -1401,7 +1401,7 @@ describe('$compile', function() {        it('should allow overriding of attribute name and remember the name', function() { -        attr.$set('ngOther', '123', 'other'); +        attr.$set('ngOther', '123', true, 'other');          expect(element.attr('other')).toEqual('123');          expect(attr.ngOther).toEqual('123'); @@ -1437,7 +1437,15 @@ describe('$compile', function() {          attr.$set('ngMyAttr', 'value');          attr.$set('ngMyAttr', null);          expect(element.attr('ng-my-attr')).toBe(undefined); -      }) +      }); + + +      it('should not set DOM element attr if writeAttr false', function() { +        attr.$set('test', 'value', false); + +        expect(element.attr('test')).toBeUndefined(); +        expect(attr.test).toBe('value'); +      });      });    }); | 
