Reputation: 167
AngularJS supports multi-element directive with -start
and -end
postfix. The official documentation only mentions ng-repeat-start
and ng-repeat-end
. Do other built-in directives support this?
For example, this works fine:
<tbody>
<tr ng-controller="myController">
<td>{{firstName}}</td>
<td>{{lastName}}</td>
</tr>
</tbody>
Both {{firstName}}
and {{lastName}}
are replaced with their proper value.
But this only works partially:
<tbody>
<tr ng-controller-start="myController">
<td>{{firstName}}</td>
</tr>
<tr ng-controller-end>
<td>{{lastName}}</td>
</tr>
</tbody>
{{firstName}}
is properly replaced. But {{lastName}}
is empty.
Since {{firstName}}
works, seems ng-controller-start
is recognized by AngularJS. Is it a bug, or I'm doing it wrong, that {{lastName}}
is not working?
Update
If ng-controller-start
and ng-controller-end
is not officially supported. How do I make ng-controller
to span multiple elements? Can I use comment-style directive? If yes, how?
Upvotes: 5
Views: 7120
Reputation: 4822
With Angular 1.2, support for multi-element directives was introduced. It seems like the specific use-case they had in mind was ngRepeat, since it wasn't promoted to be used with any of the other built-in directives as far as I am aware. With ngRepeat, however, it solved a very particular problem such as how to repeat more than one table row per item.
In 1.2, the $compile
service will detect any directive that is suffixed with -start
and assume it to be one of a pair of multi-element directive attributes (source). This leads to the undesirable side-effect that you cannot name your directive something-start
, as the $compile
service will get confused when it does not find the multi-element counterpart.
This leads to the error: Error: [$compile:uterdir] Unterminated attribute, found 'something-start' but no matching 'something-end' found.
The fact that the $compile
service is indiscriminate in treating directives as multi-element is why you are able to use ng-controller-start
and ng-controller-end
in Angular 1.2. However the ngController directive is not designed to deal with multiple elements and this is why it does not work as expected. It will act on the first element in the range, and ignore the rest - just as you observed.
Angular 1.3 fixes the above problem by requiring that any multi-element directives be explicitly defined as such by using the new multiElement: true
property on the directive definition object. See the docs on this
This means that ng-controller-start
will not do anything in 1.3, since it will cause the compiler to look for a directive named "ngControllerStart", which does not exist. Therefore the directive attribute will simply be ignored.
As the other answer points out, you can now search the angular.js GitHub repo for "multiElement" to see the specific core directives that support this feature.
Upvotes: 4
Reputation: 191799
Whether or not a directive supports this is based on its directive definition and the multiElement
property.
It doesn't seem like Angular's documentation says which built in directives are multi-element, but a Github search seems to reveal that it's only ngRepeat
, ngSwitchWhen
, ngSwitchDefault
, ngIf
, ngShow
, and ngHide
.
You can create your own directives with multiElement
as well.
Upvotes: 4