Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 11f5aee

Browse files
committed
feat($compile): change directive's restrict setting to default to EA (element/attribute)
Previously we defaulted just to A because of IE8 which had a hard time with applying css styles to HTMLUnknownElements. This is no longer the case with IE9, so we should make restrict default to EA. Doing so will make it easier to create components and avoid matching errors when creating new directives BREAKING CHANGE: directives now match elements by default unless specific restriction rules are set via `restrict` property. This means that if a directive 'myFoo' previously didn't specify matching restrictrion, it will now match both the attribute and element form. Before: <div my-foo></div> <---- my-foo attribute matched the directive <my-foo></my-foo> <---- no match After: <div my-foo></div> <---- my-foo attribute matched the directive <my-foo></my-foo> <---- my-foo element matched the directive It is not expected that this will be a problem in practice because of widespread use of prefixes that make "<my-foo>" like elements unlikely. Closes #8321
1 parent 925b208 commit 11f5aee

10 files changed

+63
-20
lines changed

src/ng/compile.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@
213213
* String of subset of `EACM` which restricts the directive to a specific directive
214214
* declaration style. If omitted, the default (attributes only) is used.
215215
*
216-
* * `E` - Element name: `<my-directive></my-directive>`
216+
* * `E` - Element name (default): `<my-directive></my-directive>`
217217
* * `A` - Attribute (default): `<div my-directive="exp"></div>`
218218
* * `C` - Class: `<div class="my-directive: exp;"></div>`
219219
* * `M` - Comment: `<!-- directive: my-directive exp -->`
@@ -581,7 +581,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
581581
directive.index = index;
582582
directive.name = directive.name || name;
583583
directive.require = directive.require || (directive.controller && directive.name);
584-
directive.restrict = directive.restrict || 'A';
584+
directive.restrict = directive.restrict || 'EA';
585585
directives.push(directive);
586586
} catch (e) {
587587
$exceptionHandler(e);

src/ng/directive/attrs.js

+1
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
351351
var normalized = directiveNormalize('ng-' + attrName);
352352
ngAttributeAliasDirectives[normalized] = function() {
353353
return {
354+
restrict: 'A',
354355
priority: 100,
355356
link: function(scope, element, attr) {
356357
scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {

src/ng/directive/input.js

+9
Original file line numberDiff line numberDiff line change
@@ -2150,6 +2150,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
21502150
*/
21512151
var ngModelDirective = function() {
21522152
return {
2153+
restrict: 'A',
21532154
require: ['ngModel', '^?form', '^?ngModelOptions'],
21542155
controller: NgModelController,
21552156
link: {
@@ -2251,6 +2252,7 @@ var ngModelDirective = function() {
22512252
* </example>
22522253
*/
22532254
var ngChangeDirective = valueFn({
2255+
restrict: 'A',
22542256
require: 'ngModel',
22552257
link: function(scope, element, attr, ctrl) {
22562258
ctrl.$viewChangeListeners.push(function() {
@@ -2262,6 +2264,7 @@ var ngChangeDirective = valueFn({
22622264

22632265
var requiredDirective = function() {
22642266
return {
2267+
restrict: 'A',
22652268
require: '?ngModel',
22662269
link: function(scope, elm, attr, ctrl) {
22672270
if (!ctrl) return;
@@ -2281,6 +2284,7 @@ var requiredDirective = function() {
22812284

22822285
var patternDirective = function() {
22832286
return {
2287+
restrict: 'A',
22842288
require: '?ngModel',
22852289
link: function(scope, elm, attr, ctrl) {
22862290
if (!ctrl) return;
@@ -2311,6 +2315,7 @@ var patternDirective = function() {
23112315

23122316
var maxlengthDirective = function() {
23132317
return {
2318+
restrict: 'A',
23142319
require: '?ngModel',
23152320
link: function(scope, elm, attr, ctrl) {
23162321
if (!ctrl) return;
@@ -2329,6 +2334,7 @@ var maxlengthDirective = function() {
23292334

23302335
var minlengthDirective = function() {
23312336
return {
2337+
restrict: 'A',
23322338
require: '?ngModel',
23332339
link: function(scope, elm, attr, ctrl) {
23342340
if (!ctrl) return;
@@ -2430,6 +2436,7 @@ var minlengthDirective = function() {
24302436
*/
24312437
var ngListDirective = function() {
24322438
return {
2439+
restrict: 'A',
24332440
require: 'ngModel',
24342441
link: function(scope, element, attr, ctrl) {
24352442
// We want to control whitespace trimming so we use this convoluted approach
@@ -2526,6 +2533,7 @@ var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
25262533
*/
25272534
var ngValueDirective = function() {
25282535
return {
2536+
restrict: 'A',
25292537
priority: 100,
25302538
compile: function(tpl, tplAttr) {
25312539
if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
@@ -2688,6 +2696,7 @@ var ngValueDirective = function() {
26882696
*/
26892697
var ngModelOptionsDirective = function() {
26902698
return {
2699+
restrict: 'A',
26912700
controller: ['$scope', '$attrs', function($scope, $attrs) {
26922701
var that = this;
26932702
this.$options = $scope.$eval($attrs.ngModelOptions);

src/ng/directive/ngBind.js

+1
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
178178
*/
179179
var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
180180
return {
181+
restrict: 'A',
181182
compile: function (tElement, tAttrs) {
182183
tElement.addClass('ng-binding');
183184

src/ng/directive/ngController.js

+1
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@
221221
*/
222222
var ngControllerDirective = [function() {
223223
return {
224+
restrict: 'A',
224225
scope: true,
225226
controller: '@',
226227
priority: 500

src/ng/directive/ngEventDirs.js

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ forEach(
4343
var directiveName = directiveNormalize('ng-' + name);
4444
ngEventDirectives[directiveName] = ['$parse', function($parse) {
4545
return {
46+
restrict: 'A',
4647
compile: function($element, attr) {
4748
var fn = $parse(attr[directiveName]);
4849
return function ngEventHandler(scope, element) {

src/ng/directive/ngRepeat.js

+1
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
212212
var NG_REMOVED = '$$NG_REMOVED';
213213
var ngRepeatMinErr = minErr('ngRepeat');
214214
return {
215+
restrict: 'A',
215216
multiElement: true,
216217
transclude: 'element',
217218
priority: 1000,

src/ng/directive/ngShowHide.js

+2
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@
157157
*/
158158
var ngShowDirective = ['$animate', function($animate) {
159159
return {
160+
restrict: 'A',
160161
multiElement: true,
161162
link: function(scope, element, attr) {
162163
scope.$watch(attr.ngShow, function ngShowWatchAction(value){
@@ -311,6 +312,7 @@ var ngShowDirective = ['$animate', function($animate) {
311312
*/
312313
var ngHideDirective = ['$animate', function($animate) {
313314
return {
315+
restrict: 'A',
314316
multiElement: true,
315317
link: function(scope, element, attr) {
316318
scope.$watch(attr.ngHide, function ngHideWatchAction(value){

src/ng/directive/select.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,11 @@ var ngOptionsMinErr = minErr('ngOptions');
135135
</example>
136136
*/
137137

138-
var ngOptionsDirective = valueFn({ terminal: true });
138+
var ngOptionsDirective = valueFn({
139+
restrict: 'A',
140+
terminal: true
141+
});
142+
139143
// jshint maxlen: false
140144
var selectDirective = ['$compile', '$parse', function($compile, $parse) {
141145
//000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888

test/ng/compileSpec.js

+40-17
Original file line numberDiff line numberDiff line change
@@ -255,14 +255,6 @@ describe('$compile', function() {
255255
}));
256256

257257

258-
it('should allow directives in comments', inject(
259-
function($compile, $rootScope, log) {
260-
element = $compile('<div>0<!-- directive: log angular -->1</div>')($rootScope);
261-
expect(log).toEqual('angular');
262-
}
263-
));
264-
265-
266258
it('should receive scope, element, and attributes', function() {
267259
var injector;
268260
module(function() {
@@ -437,20 +429,21 @@ describe('$compile', function() {
437429

438430
describe('restrict', function() {
439431

440-
it('should allow restriction of attributes', function() {
441-
module(function() {
442-
forEach({div:'E', attr:'A', clazz:'C', all:'EAC'}, function(restrict, name) {
443-
directive(name, function(log) {
432+
it('should allow restriction of availability', function () {
433+
module(function () {
434+
forEach({div: 'E', attr: 'A', clazz: 'C', comment: 'M', all: 'EACM'},
435+
function (restrict, name) {
436+
directive(name, function (log) {
444437
return {
445438
restrict: restrict,
446-
compile: valueFn(function(scope, element, attr) {
439+
compile: valueFn(function (scope, element, attr) {
447440
log(name);
448441
})
449442
};
450443
});
451444
});
452445
});
453-
inject(function($rootScope, $compile, log) {
446+
inject(function ($rootScope, $compile, log) {
454447
dealoc($compile('<span div class="div"></span>')($rootScope));
455448
expect(log).toEqual('');
456449
log.reset();
@@ -459,7 +452,7 @@ describe('$compile', function() {
459452
expect(log).toEqual('div');
460453
log.reset();
461454

462-
dealoc($compile('<attr class=""attr"></attr>')($rootScope));
455+
dealoc($compile('<attr class="attr"></attr>')($rootScope));
463456
expect(log).toEqual('');
464457
log.reset();
465458

@@ -475,8 +468,38 @@ describe('$compile', function() {
475468
expect(log).toEqual('clazz');
476469
log.reset();
477470

478-
dealoc($compile('<all class="all" all></all>')($rootScope));
479-
expect(log).toEqual('all; all; all');
471+
dealoc($compile('<!-- directive: comment -->')($rootScope));
472+
expect(log).toEqual('comment');
473+
log.reset();
474+
475+
dealoc($compile('<all class="all" all><!-- directive: all --></all>')($rootScope));
476+
expect(log).toEqual('all; all; all; all');
477+
});
478+
});
479+
480+
481+
it('should use EA rule as the default', function () {
482+
module(function () {
483+
directive('defaultDir', function (log) {
484+
return {
485+
compile: function () {
486+
log('defaultDir');
487+
}
488+
};
489+
});
490+
});
491+
inject(function ($rootScope, $compile, log) {
492+
dealoc($compile('<span default-dir ></span>')($rootScope));
493+
expect(log).toEqual('defaultDir');
494+
log.reset();
495+
496+
dealoc($compile('<default-dir></default-dir>')($rootScope));
497+
expect(log).toEqual('defaultDir');
498+
log.reset();
499+
500+
dealoc($compile('<span class="default-dir"></span>')($rootScope));
501+
expect(log).toEqual('');
502+
log.reset();
480503
});
481504
});
482505
});

0 commit comments

Comments
 (0)