fix($compile): set attribute value even if ngAttr* contains no interpolation
Previoulsy, when the value of an `ngAttrXyz` attribute did not contain any interpolation, then the `xyz` attribute was never set. BTW, this commit adds a negligible overhead (since we have to set up a one-time watcher for example), but it is justifiable for someone that is using `ngAttrXyz` (instead of `xyz` directly). (There is also some irrelevant refactoring to remove unnecessary dependencies from tests.) Fixes #15133 Closes #15149
This commit is contained in:
+4
-4
@@ -3240,16 +3240,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
}
|
||||
|
||||
|
||||
function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
|
||||
function addAttrInterpolateDirective(node, directives, value, name, isNgAttr) {
|
||||
var trustedContext = getTrustedContext(node, name);
|
||||
allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;
|
||||
var mustHaveExpression = !isNgAttr;
|
||||
var allOrNothing = ALL_OR_NOTHING_ATTRS[name] || isNgAttr;
|
||||
|
||||
var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);
|
||||
var interpolateFn = $interpolate(value, mustHaveExpression, trustedContext, allOrNothing);
|
||||
|
||||
// no interpolation found -> ignore
|
||||
if (!interpolateFn) return;
|
||||
|
||||
|
||||
if (name === 'multiple' && nodeName_(node) === 'select') {
|
||||
throw $compileMinErr('selmulti',
|
||||
'Binding to the \'multiple\' attribute is not supported. Element: {0}',
|
||||
|
||||
+51
-40
@@ -11151,8 +11151,7 @@ describe('$compile', function() {
|
||||
}
|
||||
|
||||
describe('ngAttr* attribute binding', function() {
|
||||
|
||||
it('should bind after digest but not before', inject(function($compile, $rootScope) {
|
||||
it('should bind after digest but not before', inject(function() {
|
||||
$rootScope.name = 'Misko';
|
||||
element = $compile('<span ng-attr-test="{{name}}"></span>')($rootScope);
|
||||
expect(element.attr('test')).toBeUndefined();
|
||||
@@ -11160,7 +11159,7 @@ describe('$compile', function() {
|
||||
expect(element.attr('test')).toBe('Misko');
|
||||
}));
|
||||
|
||||
it('should bind after digest but not before when after overridden attribute', inject(function($compile, $rootScope) {
|
||||
it('should bind after digest but not before when after overridden attribute', inject(function() {
|
||||
$rootScope.name = 'Misko';
|
||||
element = $compile('<span test="123" ng-attr-test="{{name}}"></span>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
@@ -11168,7 +11167,7 @@ describe('$compile', function() {
|
||||
expect(element.attr('test')).toBe('Misko');
|
||||
}));
|
||||
|
||||
it('should bind after digest but not before when before overridden attribute', inject(function($compile, $rootScope) {
|
||||
it('should bind after digest but not before when before overridden attribute', inject(function() {
|
||||
$rootScope.name = 'Misko';
|
||||
element = $compile('<span ng-attr-test="{{name}}" test="123"></span>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
@@ -11176,7 +11175,15 @@ describe('$compile', function() {
|
||||
expect(element.attr('test')).toBe('Misko');
|
||||
}));
|
||||
|
||||
it('should remove attribute if any bindings are undefined', inject(function($compile, $rootScope) {
|
||||
it('should set the attribute (after digest) even if there is no interpolation', inject(function() {
|
||||
element = $compile('<span ng-attr-test="foo"></span>')($rootScope);
|
||||
expect(element.attr('test')).toBeUndefined();
|
||||
|
||||
$rootScope.$digest();
|
||||
expect(element.attr('test')).toBe('foo');
|
||||
}));
|
||||
|
||||
it('should remove attribute if any bindings are undefined', inject(function() {
|
||||
element = $compile('<span ng-attr-test="{{name}}{{emphasis}}"></span>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(element.attr('test')).toBeUndefined();
|
||||
@@ -11189,6 +11196,8 @@ describe('$compile', function() {
|
||||
}));
|
||||
|
||||
describe('in directive', function() {
|
||||
var log;
|
||||
|
||||
beforeEach(module(function() {
|
||||
directive('syncTest', function(log) {
|
||||
return {
|
||||
@@ -11209,47 +11218,52 @@ describe('$compile', function() {
|
||||
});
|
||||
}));
|
||||
|
||||
beforeEach(inject(function($templateCache) {
|
||||
beforeEach(inject(function($templateCache, _log_) {
|
||||
log = _log_;
|
||||
$templateCache.put('async.html', '<h1>Test</h1>');
|
||||
}));
|
||||
|
||||
it('should provide post-digest value in synchronous directive link functions when after overridden attribute',
|
||||
inject(function(log, $rootScope, $compile) {
|
||||
$rootScope.test = 'TEST';
|
||||
element = $compile('<div sync-test test="123" ng-attr-test="{{test}}"></div>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
expect(log.toArray()).toEqual(['TEST', 'TEST']);
|
||||
}));
|
||||
function() {
|
||||
$rootScope.test = 'TEST';
|
||||
element = $compile('<div sync-test test="123" ng-attr-test="{{test}}"></div>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
expect(log.toArray()).toEqual(['TEST', 'TEST']);
|
||||
}
|
||||
);
|
||||
|
||||
it('should provide post-digest value in synchronous directive link functions when before overridden attribute',
|
||||
inject(function(log, $rootScope, $compile) {
|
||||
$rootScope.test = 'TEST';
|
||||
element = $compile('<div sync-test ng-attr-test="{{test}}" test="123"></div>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
expect(log.toArray()).toEqual(['TEST', 'TEST']);
|
||||
}));
|
||||
function() {
|
||||
$rootScope.test = 'TEST';
|
||||
element = $compile('<div sync-test ng-attr-test="{{test}}" test="123"></div>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
expect(log.toArray()).toEqual(['TEST', 'TEST']);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
it('should provide post-digest value in asynchronous directive link functions when after overridden attribute',
|
||||
inject(function(log, $rootScope, $compile) {
|
||||
$rootScope.test = 'TEST';
|
||||
element = $compile('<div async-test test="123" ng-attr-test="{{test}}"></div>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
$rootScope.$digest();
|
||||
expect(log.toArray()).toEqual(['TEST', 'TEST']);
|
||||
}));
|
||||
function() {
|
||||
$rootScope.test = 'TEST';
|
||||
element = $compile('<div async-test test="123" ng-attr-test="{{test}}"></div>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
$rootScope.$digest();
|
||||
expect(log.toArray()).toEqual(['TEST', 'TEST']);
|
||||
}
|
||||
);
|
||||
|
||||
it('should provide post-digest value in asynchronous directive link functions when before overridden attribute',
|
||||
inject(function(log, $rootScope, $compile) {
|
||||
$rootScope.test = 'TEST';
|
||||
element = $compile('<div async-test ng-attr-test="{{test}}" test="123"></div>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
$rootScope.$digest();
|
||||
expect(log.toArray()).toEqual(['TEST', 'TEST']);
|
||||
}));
|
||||
function() {
|
||||
$rootScope.test = 'TEST';
|
||||
element = $compile('<div async-test ng-attr-test="{{test}}" test="123"></div>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
$rootScope.$digest();
|
||||
expect(log.toArray()).toEqual(['TEST', 'TEST']);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('should work with different prefixes', inject(function($compile, $rootScope) {
|
||||
it('should work with different prefixes', inject(function() {
|
||||
$rootScope.name = 'Misko';
|
||||
element = $compile('<span ng:attr:test="{{name}}" ng-Attr-test2="{{name}}" ng_Attr_test3="{{name}}"></span>')($rootScope);
|
||||
expect(element.attr('test')).toBeUndefined();
|
||||
@@ -11261,14 +11275,14 @@ describe('$compile', function() {
|
||||
expect(element.attr('test3')).toBe('Misko');
|
||||
}));
|
||||
|
||||
it('should work with the "href" attribute', inject(function($compile, $rootScope) {
|
||||
it('should work with the "href" attribute', inject(function() {
|
||||
$rootScope.value = 'test';
|
||||
element = $compile('<a ng-attr-href="test/{{value}}"></a>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
expect(element.attr('href')).toBe('test/test');
|
||||
}));
|
||||
|
||||
it('should work if they are prefixed with x- or data- and different prefixes', inject(function($compile, $rootScope) {
|
||||
it('should work if they are prefixed with x- or data- and different prefixes', inject(function() {
|
||||
$rootScope.name = 'Misko';
|
||||
element = $compile('<span data-ng-attr-test2="{{name}}" x-ng-attr-test3="{{name}}" data-ng:attr-test4="{{name}}" ' +
|
||||
'x_ng-attr-test5="{{name}}" data:ng-attr-test6="{{name}}"></span>')($rootScope);
|
||||
@@ -11286,8 +11300,7 @@ describe('$compile', function() {
|
||||
}));
|
||||
|
||||
describe('when an attribute has a dash-separated name', function() {
|
||||
|
||||
it('should work with different prefixes', inject(function($compile, $rootScope) {
|
||||
it('should work with different prefixes', inject(function() {
|
||||
$rootScope.name = 'JamieMason';
|
||||
element = $compile('<span ng:attr:dash-test="{{name}}" ng-Attr-dash-test2="{{name}}" ng_Attr_dash-test3="{{name}}"></span>')($rootScope);
|
||||
expect(element.attr('dash-test')).toBeUndefined();
|
||||
@@ -11299,7 +11312,7 @@ describe('$compile', function() {
|
||||
expect(element.attr('dash-test3')).toBe('JamieMason');
|
||||
}));
|
||||
|
||||
it('should work if they are prefixed with x- or data-', inject(function($compile, $rootScope) {
|
||||
it('should work if they are prefixed with x- or data-', inject(function() {
|
||||
$rootScope.name = 'JamieMason';
|
||||
element = $compile('<span data-ng-attr-dash-test2="{{name}}" x-ng-attr-dash-test3="{{name}}" data-ng:attr-dash-test4="{{name}}"></span>')($rootScope);
|
||||
expect(element.attr('dash-test2')).toBeUndefined();
|
||||
@@ -11328,7 +11341,6 @@ describe('$compile', function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should keep attributes ending with -end single-element directives', function() {
|
||||
module(function($compileProvider) {
|
||||
$compileProvider.directive('dashEnder', function(log) {
|
||||
@@ -11346,7 +11358,6 @@ describe('$compile', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user