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

Commit f6d7010

Browse files
committed
feat($compile): added new method strictComponentBindingsEnabled
1 parent e6d5fe7 commit f6d7010

File tree

3 files changed

+127
-3
lines changed

3 files changed

+127
-3
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@ngdoc error
2+
@name $compile:missingattr
3+
@fullName Missing required attribute
4+
@description
5+
6+
This error may occur only when `$compileProvider.strictComponentBindingsEnabled` is set to `true`.han all attributes without `?` must be set. If one or more aren't set than first one will throw an error.

src/ng/compile.js

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,6 +1403,32 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
14031403
return debugInfoEnabled;
14041404
};
14051405

1406+
/**
1407+
* @ngdoc method
1408+
* @name $compileProvider#strictComponentBindingsEnabled
1409+
*
1410+
* @param {boolean=} enabled update the strictComponentBindingsEnabled state if provided, otherwise just return the
1411+
* current strictComponentBindingsEnabled state
1412+
* @returns {*} current value if used as getter or itself (chaining) if used as setter
1413+
*
1414+
* @kind function
1415+
*
1416+
* @description
1417+
* Call this method to enable/disable strict component bindings check. If enabled, the compiler will enforce that
1418+
* for all bindings of a component that are not set as optional with `?`, an attribute needs to be provided
1419+
* on the component's HTML tag.
1420+
*
1421+
* The default value is false.
1422+
*/
1423+
var strictComponentBindingsEnabled = false;
1424+
this.strictComponentBindingsEnabled = function(enabled) {
1425+
if (isDefined(enabled)) {
1426+
strictComponentBindingsEnabled = enabled;
1427+
return this;
1428+
}
1429+
return strictComponentBindingsEnabled;
1430+
};
1431+
14061432
var TTL = 10;
14071433
/**
14081434
* @ngdoc method
@@ -3430,7 +3456,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
34303456

34313457
case '@':
34323458
if (!optional && !hasOwnProperty.call(attrs, attrName)) {
3433-
destination[scopeName] = attrs[attrName] = undefined;
3459+
if (strictComponentBindingsEnabled) {
3460+
throw $compileMinErr('missingattr',
3461+
'Attribute \'{0}\' of \'{1}\' is non-optional and must be set!',
3462+
attrName, directive.name);
3463+
} else {
3464+
destination[scopeName] = attrs[attrName] = undefined;
3465+
}
34343466
}
34353467
removeWatch = attrs.$observe(attrName, function(value) {
34363468
if (isString(value) || isBoolean(value)) {
@@ -3457,7 +3489,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
34573489
case '=':
34583490
if (!hasOwnProperty.call(attrs, attrName)) {
34593491
if (optional) break;
3460-
attrs[attrName] = undefined;
3492+
if (strictComponentBindingsEnabled) {
3493+
throw $compileMinErr('missingattr',
3494+
'Attribute \'{0}\' of \'{1}\' is non-optional and must be set!',
3495+
attrName, directive.name);
3496+
} else {
3497+
attrs[attrName] = undefined;
3498+
}
34613499
}
34623500
if (optional && !attrs[attrName]) break;
34633501

@@ -3501,7 +3539,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
35013539
case '<':
35023540
if (!hasOwnProperty.call(attrs, attrName)) {
35033541
if (optional) break;
3504-
attrs[attrName] = undefined;
3542+
if (strictComponentBindingsEnabled) {
3543+
throw $compileMinErr('missingattr',
3544+
'Attribute \'{0}\' of \'{1}\' is non-optional and must be set!',
3545+
attrName, directive.name);
3546+
} else {
3547+
attrs[attrName] = undefined;
3548+
}
35053549
}
35063550
if (optional && !attrs[attrName]) break;
35073551

@@ -3526,6 +3570,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
35263570
break;
35273571

35283572
case '&':
3573+
if (!hasOwnProperty.call(attrs, attrName) && !optional && strictComponentBindingsEnabled) {
3574+
throw $compileMinErr('missingattr',
3575+
'Attribute \'{0}\' of \'{1}\' is non-optional and must be set!',
3576+
attrName, directive.name);
3577+
}
35293578
// Don't assign Object.prototype method to scope
35303579
parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
35313580

test/ng/compileSpec.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,15 @@ describe('$compile', function() {
169169
inject();
170170
});
171171

172+
it('should allow strictComponentBindingsEnabled to be configured', function() {
173+
module(function($compileProvider) {
174+
expect($compileProvider.strictComponentBindingsEnabled()).toBe(false); // the default
175+
$compileProvider.strictComponentBindingsEnabled(true);
176+
expect($compileProvider.strictComponentBindingsEnabled()).toBe(true);
177+
});
178+
inject();
179+
});
180+
172181
it('should allow onChangesTtl to be configured', function() {
173182
module(function($compileProvider) {
174183
expect($compileProvider.onChangesTtl()).toBe(10); // the default
@@ -2854,6 +2863,21 @@ describe('$compile', function() {
28542863
})
28552864
);
28562865

2866+
it('should throw an error for undefined non-optional "=" bindings when strictComponentBindingsEnabled is true', function() {
2867+
module(function($compileProvider) {
2868+
$compileProvider.strictComponentBindingsEnabled(true);
2869+
});
2870+
inject(
2871+
function($rootScope, $compile) {
2872+
var func = function() {
2873+
element = $compile(
2874+
'<div prototype-method-name-as-scope-var-a></div>'
2875+
)($rootScope);
2876+
};
2877+
expect(func).toThrowMinErr('$compile', 'missingattr', 'Attribute \'valueOf\' of \'prototypeMethodNameAsScopeVarA\' is non-optional and must be set!');
2878+
});
2879+
});
2880+
28572881
it('should handle "@" bindings with same method names in Object.prototype correctly when not present', inject(
28582882
function($rootScope, $compile) {
28592883
var func = function() {
@@ -2891,6 +2915,21 @@ describe('$compile', function() {
28912915
})
28922916
);
28932917

2918+
it('should throw an error for undefined non-optional "@" bindings when strictComponentBindingsEnabled is true', function() {
2919+
module(function($compileProvider) {
2920+
$compileProvider.strictComponentBindingsEnabled(true);
2921+
});
2922+
inject(
2923+
function($rootScope, $compile) {
2924+
var func = function() {
2925+
element = $compile(
2926+
'<div prototype-method-name-as-scope-var-b></div>'
2927+
)($rootScope);
2928+
};
2929+
expect(func).toThrowMinErr('$compile', 'missingattr', 'Attribute \'valueOf\' of \'prototypeMethodNameAsScopeVarB\' is non-optional and must be set!');
2930+
});
2931+
});
2932+
28942933
it('should handle "&" bindings with same method names in Object.prototype correctly when not present', inject(
28952934
function($rootScope, $compile) {
28962935
var func = function() {
@@ -2923,6 +2962,36 @@ describe('$compile', function() {
29232962
})
29242963
);
29252964

2965+
it('should throw an error for undefined non-optional "&" bindings when strictComponentBindingsEnabled is true', function() {
2966+
module(function($compileProvider) {
2967+
$compileProvider.strictComponentBindingsEnabled(true);
2968+
});
2969+
inject(
2970+
function($rootScope, $compile) {
2971+
var func = function() {
2972+
element = $compile(
2973+
'<div prototype-method-name-as-scope-var-c></div>'
2974+
)($rootScope);
2975+
};
2976+
expect(func).toThrowMinErr('$compile', 'missingattr', 'Attribute \'valueOf\' of \'prototypeMethodNameAsScopeVarC\' is non-optional and must be set!');
2977+
});
2978+
});
2979+
2980+
it('should throw an error for undefined non-optional "&" bindings when strictComponentBindingsEnabled is true', function() {
2981+
module(function($compileProvider) {
2982+
$compileProvider.strictComponentBindingsEnabled(true);
2983+
});
2984+
inject(
2985+
function($rootScope, $compile) {
2986+
var func = function() {
2987+
element = $compile(
2988+
'<div watch-as-scope-var></div>'
2989+
)($rootScope);
2990+
};
2991+
expect(func).toThrowMinErr('$compile', 'missingattr', 'Attribute \'watch\' of \'watchAsScopeVar\' is non-optional and must be set!');
2992+
});
2993+
});
2994+
29262995
it('should not throw exception when using "watch" as binding in Firefox', inject(
29272996
function($rootScope, $compile) {
29282997
$rootScope.watch = 'watch';

0 commit comments

Comments
 (0)