ngSwitchWhen Priority Is Higher Than ngRepeat Priority In AngularJS 1.3
This is a really minor post about a change in directive priority in AngularJS 1.3. The other day, in my post about using multiple templates in a single ngRepeat directive, Boris Litvinsky brought it to my attention that ngSwitchWhen now executes at a higher priority (1,200) than the ngRepeat directive (1,000). While it wasn't necessarily relevant to my previous post, it does mean that as of AngularJS 1.3, the ngSwitchWhen directive can now be used to conditionally link ngRepeat directives.
Run this demo in my JavaScript Demos project on GitHub.
Prior to AngularJS 1.3, the ngSwitchWhen directive used to execute at priority 800. This means that if you used it on the same element as ngRepeat (priority 1,000), it would transclude the element after ngRepeat had cloned it. It would then attempt to link the second clone in the context of ngSwitch, which is absolutely not what the developer was intending.
As of AngularJS 1.3, the ngSwitchWhen directive executes at priority 1,200 which means that it executes before ngRepeat. As such, the ngSwitchWhen directive can now work in conjunction with the ngSwitch directive to conditionally include an ngRepeat block:
<!doctype html>
<html ng-app="Demo">
<head>
<meta charset="utf-8" />
<title>
ngSwitchWhen Priority Is Higher Than ngRepeat Priority In AngularJS 1.3
</title>
</head>
<body ng-controller="AppController">
<h1>
ngSwitchWhen Priority Is Higher Than ngRepeat Priority In AngularJS 1.3
</h1>
<h2>
Friends
</h2>
<ul ng-switch="!! friends">
<!-- Data is still loading. -->
<li ng-switch-when="false">
<em>Loading data...</em>
</li>
<!--
Data has loaded and is ready to render.
--
As of AngularJS 1.3, ngSwitchWhen has a priority of 1,200, which is higher
than ngRepeat (which has priority 1,000). As such, the ngSwitchWhen will
determine whether or not the LI element is ultimately linked. Then, once it's
linked, the ngRepeat directive will determine if it's repeatedly cloned.
PRIOR to AngularJS 1.3, the ngSwitchWhen would have linked AFTER the
ngRepeat. However, since it transcludes its content and then gets it linked
in the context of the ngSwitch Scope, you end up bypassing the ngRepeat
scope for the second transclusion... which is only PART of what makes double-
transclusion a difficult use-case (in this case).
-->
<li
ng-switch-when="true"
ng-repeat="friend in friends">
{{ friend.name }}
</li>
</div>
<!-- Load scripts. -->
<script type="text/javascript" src="../../vendor/angularjs/angular-1.3.8.min.js"></script>
<script type="text/javascript">
// Create an application module for our demo.
var app = angular.module( "Demo", [] );
// -------------------------------------------------- //
// -------------------------------------------------- //
// I control the root of the application.
app.controller(
"AppController",
function( $scope, $timeout ) {
$scope.friends = null;
// Defer the definition of the data so that we can simulate a loading
// state while data "comes over the wire."
$timeout(
function deferLoading() {
$scope.friends = [
{
id: 1,
name: "Sarah"
},
{
id: 2,
name: "Tricia"
},
{
id: 3,
name: "Kim"
}
];
},
( 2 * 1000 )
);
}
);
</script>
</body>
</html>
Personally, I've never run into this limitation (and I'm still on AngularJS 1.0.8 in production). I've never needed to put ngSwitchWhen and ngRepeat on the same element. Typically, I would put ngSwitchWhen on a container and then have the ngRepeat as part of the descendant content. That said, I'm sure there are use-cases where this is a valuable change. And, it's good to see the AngularJS team continually refining and optimizing their directives.
Want to use code from this post? Check out the license.
Reader Comments
Intresting, thanks Ben And Boris!
@Chen,
No problem - happy to help clarify anything. Cheers!
I've compiled a list of angular directives according to their priorities.
Also, I've included terminal property for each directive that asserts it
https://gist.github.com/awerlang/fea0da3b61cf1f4b1a8a
Hope it helps someone
@André,
Very cool! One thing, though - I believe that ngSwitch is actually at priority:0. It's only the ngSwitchWhen / ngSwitchDefault that is now at priority:1,200.