[AngularJS] Reusable directive, require from parent controller

Glorious Directives for Our Navigation

NoteWrangler navigation has now been broken into two parts: the children — nw-nav-item — and the parent — nw-nav.

Help the children and parent communicate by using what we have learned about $scope and link. They'll need to function as a nav should when clicked.

Create a default activeNav variable on nwNav's $scope and make it default to'Notes'.

angular.module('NoteWrangler')
.directive('nwNav', function() {
  return {
    restrict: 'E',
    controller: function($scope) {
      $scope.activeNav = 'Notes';
      
    }
  };
});

 

Create a function called getActiveNav in the controller of the nw-nav directive that returns the value of $scope.activeNav variable.

angular.module('NoteWrangler')
.directive('nwNav', function() {
  return {
    restrict: 'E',
    controller: function($scope) {
      $scope.activeNav = 'Notes';
      this.getActiveNav= function(){
          return $scope.activeNav;
      };
    }
  };
});

 

Create a function called setActiveNav on the controller of the nw-nav directive that sets the value of $scope.activeNav variable.

angular.module('NoteWrangler')
.directive('nwNav', function() {
  return {
    restrict: 'E',
    controller: function($scope) {
      $scope.activeNav = 'Notes';
      this.getActiveNav= function(){
          return $scope.activeNav;
      };
      this.setActiveNav = function(note){
          $scope.activeNav = note;
      };
    }
  };
});

 

return this to the controller:

angular.module('NoteWrangler')
.directive('nwNav', function() {
  return {
    restrict: 'E',
    controller: function($scope) {
      $scope.activeNav = 'Notes';
      this.getActiveNav= function(){
          return $scope.activeNav;
      };
      this.setActiveNav = function(note){
          $scope.activeNav = note;
      };
      
      return this;
    }
  };
});

 

The Parent Is Required

The nwNavItem directive needs to be able to communicate with the parentnwNav directive in order to tell when a nav item should be active. Let's go ahead and set that up.

Within the nwNavItem directive, use the require option to gain access to the controller from the parent nwNav directive.

angular.module('NoteWrangler')
.directive('nwNavItem', function() {
  return {
    restrict: 'E',
    templateUrl: './templates/directives/nw-nav-item.html',
    require: '^nwNav'
  };
});

 

Give the nwNavItem directive a link function. Make sure to fill in all the arguments so that we have access to the controller required from the previous task.

angular.module('NoteWrangler')
.directive('nwNavItem', function() {
  return {
    restrict: 'E',
    templateUrl: './templates/directives/nw-nav-item.html',
    require: '^nwNav',
    link: function(scope, element, attrs, nwNavCtrl){
        
    }
  };
});

 

Using Parent Functionality

We've created the isActive() and activate() functions on the scope of the nwNavItem directive. Within these functions, we'll need to access the controller of the nwNav directive to set and get which nav item is active.

First, we need a name for the nav item to work. Create a new isolate scope on thenwNavItem directive and allow it to accept an attribute (@) value called name.

angular.module('NoteWrangler')
.directive('nwNavItem', function() {
  return {
    restrict: 'E',
    templateUrl: './templates/directives/nw-nav-item.html',
    require: '^nwNav',
    link: function(scope, element, attrs, nwNavCtrl) {
      scope.isActive = function() {

      };

      scope.activate = function() {

      };
    },
    scope: {
      name: '@'
    }
  };
});

 

Within the isActive() function, call the getActiveNav() function from the requiredcontroller to get the current active nav value. Compare the return value from the controller with the scope.name value and return the result from the isActivefunction.

angular.module('NoteWrangler')
.directive('nwNavItem', function() {
  return {
    restrict: 'E',
    templateUrl: './templates/directives/nw-nav-item.html',
    require: '^nwNav',
    link: function(scope, element, attrs, nwNavCtrl) {
      scope.isActive = function() {
                return nwNavCtrl.getActiveNav()==scope.name;
      };

      scope.activate = function() {

      };
    },
    scope: {
      name: '@'
    }
  };
});

 

We need a way to set the active nav value when a nav item is clicked. In ouractivate() function, call the setActiveNav() function on the require'd controller and pass the scope.name as an argument.

angular.module('NoteWrangler')
.directive('nwNavItem', function() {
  return {
    restrict: 'E',
    templateUrl: './templates/directives/nw-nav-item.html',
    require: '^nwNav',
    link: function(scope, element, attrs, nwNavCtrl) {
      scope.isActive = function() {
                return nwNavCtrl.getActiveNav()==scope.name;
      };

      scope.activate = function() {
                nwNavCtrl.setActiveNav(scope.name);
      };
    },
    scope: {
      name: '@'
    }
  };
});

 

The Magic Revealed 

Now that we have our nav directives working, we need to hook up the templates.

We can see in the index.html that we're already passing Notes and Users to thename attribute of our nav item directive. Use data binding to display the value ofscope.name as the content of our a tag.

<a class="list-item" href="#/">{{name}}</a>

 

Give each nwNavItem a class of active if it isActive().

<a class="list-item" ng-class="{'active': isActive()}" href="#/">{{name}}</a>

 

On click, call the activate() method.

<a class="list-item" ng-class="{'active': isActive()}" ng-click="activate()" href="#/">{{name}}</a>

 

Create an href for each nav item with a dynamic path using the name variable. The route should look like: #/value_of_scope_dot_name and use data binding.

<a class="list-item" ng-class="{'active': isActive()}" ng-click="activate()" href="#/{{name}}">{{name}}</a>

 

Notice that routes are case sensitive. When we click on Users, it finds no route for/Users, and therefore redirects to /notes. Solve this issue by using a lowercasefilter on the name binding within the route.

<a class="list-item" ng-class="{'active': isActive()}" ng-click="activate()" href="#/{{name | lowercase}}">{{name}}</a>

 

Since we've added an expression to the href attribute of our a tag, we need to change it to ng-href attribute. Check out the docs to see why this is important.

<a class="list-item" ng-class="{'active': isActive()}" ng-click="activate()" ng-href="#/{{name | lowercase}}">{{name}}</a>

 

posted @ 2015-03-09 04:03  Zhentiw  阅读(733)  评论(0编辑  收藏  举报