The final example illustrates how you can nest directives within each other and have them interact. Nesting directives is a great way to provide a parent context and container for custom elements that are related to each other. In this example the outer directive myPhotos
acts as a container that can contain child directives named myPhoto
.
Listing 7.5 implements two custom directives: myPhotos
and myPhoto
. The myPhotos
directive is designed to be a container for the myPhoto
directive. Notice that lines 7–18 define a controller that provides the functionality for the myPhotos
directive, including an addPhoto()
function. Because the code uses require:'^myPhotos'
in the myPhoto
directive, you can also call the addPhoto()
method from the link()
function by using the photosControl
handle to the myPhotos
controller.
Listing 7.6 implements the myPhotos
and myPhoto
directives in an AngularJS template. The myPhoto
directives are nested inside the myPhotos
directive. Notice that the title
attribute is set on each myPhoto
directive and linked to the scope in line 28 of Listing 7.5.
Listing 7.7 implements a partial template loaded by the myPhotos
directive. It generates a <div>
container and then uses the photos
array in the myPhotos
scope to build a list of links bound to the select()
function, using ng-click
. <div ng-transclude></div>
provides the container for the myPhoto
child elements.
Figure 7.3 shows the web page created by Listings 7.5, 7.6, and 7.7.
01 angular.module('myApp', [])
02 .directive('myPhotos', function() {
03 return {
04 restrict: 'E',
05 transclude: true,
06 scope: {},
07 controller: function($scope) {
08 var photos = $scope.photos = [];
09 $scope.select = function(photo) {
10 angular.forEach(photos, function(photo) {
11 photo.selected = false;
12 });
13 photo.selected = true;
14 };
15 this.addPhoto = function(photo) {
16 photos.push(photo);
17 };
18 },
19 templateUrl: 'my_photos.html'
20 };
21 })
22 .directive('myPhoto', function() {
23 return {
24 require: '^myPhotos',
25 restrict: 'E',
26 transclude: true,
27 scope: { title: '@'},
28 link: function(scope, elem, attrs, photosControl) {
29 photosControl.addPhoto(scope);
30 },
31 template: '<div ng-show="selected" ng-transclude></div>'
32 };
33 });
01 <!doctype html>
02 <html ng-app="myApp">
03 <head>
04 <title>AngularJS Custom Directive</title>
05 <style>
06 img { width: 300px }
07 </style>
08 </head>
09 <body>
10 <h2>Custom Directive Photo Flip</h2>
11 <my-photos>
12 <my-photo title="Flower">
13 <img src="/images/flower.jpg"/>
14 </my-photo>
15 <my-photo title="Arch">
16 <img src="/images/arch.jpg"/>
17 </my-photo>
18 <my-photo title="Lake">
19 <img src="/images/lake.jpg"/>
20 </my-photo>
21 <my-photo title="Bison">
22 <img src="/images/bison.jpg"/>
23 </my-photo>
24 </my-photos>
25 <script src="http://code.angularjs.org/1.3.0/angular.min.js"></script>
26 <script src="js/directive_custom_photos.js"></script>
27 </body>
28 </html>
01 <div>
02 <span ng-repeat="photo in photos"
03 ng-class="{active:photo.selected}">
04 <a href="" ng-click="select(photo)">{{photo.title}}</a>
05 </span>
06 <div ng-transclude></div>
07 </div>