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

Commit 632b2dd

Browse files
committed
fix($controller): throw better error when controller expression is bad
Previously, the error was a JS runtime error when trying to access a property of `null`. But, it's a bit nicer to throw a real error and provide a description of how to fix it. Developer ergonomics and all that. Closes #10875 Closes #10910
1 parent 7caad22 commit 632b2dd

File tree

3 files changed

+96
-2
lines changed

3 files changed

+96
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
@ngdoc error
2+
@name $controller:ctrlfmt
3+
@fullName Badly formed controller string
4+
@description
5+
6+
This error occurs when {@link ng.$controller $controller} service is called
7+
with a string that does not match the supported controller string formats.
8+
9+
Supported formats:
10+
11+
1. `__name__`
12+
2. `__name__ as __identifier__`
13+
14+
N'either `__name__` or `__identifier__` may contain spaces.
15+
16+
Example of incorrect usage that leads to this error:
17+
```html
18+
<!-- unclosed ng-controller attribute messes up the format -->
19+
<div ng-controller="myController>
20+
```
21+
22+
or
23+
24+
```js
25+
// does not match `__name__` or `__name__ as __identifier__`
26+
var myCtrl = $controller("mY contRoller", { $scope: newScope });
27+
```
28+
29+
or
30+
31+
```js
32+
directive("myDirective", function() {
33+
return {
34+
// does not match `__name__` or `__name__ as __identifier__`
35+
controller: "mY contRoller",
36+
link: function() {}
37+
};
38+
});
39+
```
40+
41+
To fix the examples above, ensure that the controller string matches the supported
42+
formats, and that any html attributes which are used as controller expressions are
43+
closed.
44+
45+
46+
Please consult the {@link ng.$controller $controller} service api docs to learn more.

src/ng/controller.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict';
22

3+
var $controllerMinErr = minErr('$controller');
4+
35
/**
46
* @ngdoc provider
57
* @name $controllerProvider
@@ -87,7 +89,12 @@ function $ControllerProvider() {
8789
}
8890

8991
if (isString(expression)) {
90-
match = expression.match(CNTRL_REG),
92+
match = expression.match(CNTRL_REG);
93+
if (!match) {
94+
throw new $controllerMinErr('ctrlfmt',
95+
"Badly formed controller string '{0}'. " +
96+
"Must match `__name__ as __id__` or `__name__`.", expression);
97+
}
9198
constructor = match[1],
9299
identifier = identifier || match[3];
93100
expression = controllers.hasOwnProperty(constructor)

test/ng/controllerSpec.js

+42-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,16 @@ describe('$controller', function() {
9090
var foo = $controller('a.Foo', {$scope: scope});
9191
expect(foo).toBeDefined();
9292
expect(foo instanceof Foo).toBe(true);
93-
}));
93+
}));
94+
95+
96+
it('should throw ctrlfmt if name contains spaces', function() {
97+
expect(function() {
98+
$controller('ctrl doom');
99+
}).toThrowMinErr("$controller", "ctrlfmt",
100+
"Badly formed controller string 'ctrl doom'. " +
101+
"Must match `__name__ as __id__` or `__name__`.");
102+
});
94103
});
95104

96105

@@ -168,5 +177,37 @@ describe('$controller', function() {
168177
}).toThrowMinErr("$controller", "noscp", "Cannot export controller 'a.b.FooCtrl' as 'foo'! No $scope object provided via `locals`.");
169178

170179
});
180+
181+
182+
it('should throw ctrlfmt if identifier contains non-ident characters', function() {
183+
expect(function() {
184+
$controller('ctrl as foo<bar');
185+
}).toThrowMinErr("$controller", "ctrlfmt",
186+
"Badly formed controller string 'ctrl as foo<bar'. " +
187+
"Must match `__name__ as __id__` or `__name__`.");
188+
});
189+
190+
191+
it('should throw ctrlfmt if identifier contains spaces', function() {
192+
expect(function() {
193+
$controller('ctrl as foo bar');
194+
}).toThrowMinErr("$controller", "ctrlfmt",
195+
"Badly formed controller string 'ctrl as foo bar'. " +
196+
"Must match `__name__ as __id__` or `__name__`.");
197+
});
198+
199+
200+
it('should throw ctrlfmt if identifier missing after " as "', function() {
201+
expect(function() {
202+
$controller('ctrl as ');
203+
}).toThrowMinErr("$controller", "ctrlfmt",
204+
"Badly formed controller string 'ctrl as '. " +
205+
"Must match `__name__ as __id__` or `__name__`.");
206+
expect(function() {
207+
$controller('ctrl as');
208+
}).toThrowMinErr("$controller", "ctrlfmt",
209+
"Badly formed controller string 'ctrl as'. " +
210+
"Must match `__name__ as __id__` or `__name__`.");
211+
});
171212
});
172213
});

0 commit comments

Comments
 (0)