Monday, October 19, 2015

Making a page nav directive in Angular JS

In this post I will be explaining how I created a page nav directive in AngularJS.  The page nav is a navigation header on the webpage.  Here is what facebook's top nav looks like:
Its just going to be that top bar that shows up at the top of every page..

Angular JS has a nifty feature called 'directives'.  This is where you can specify your own custom HTML tag.  The tag could be anything...a header nav for example.  Then in your pages you can simply use this directive to display your nav.

So How do we go about creating this directive for this nav?  

Here we go:

First, I am going to create a project file structure to keep my project organized.  This is the one I am using:

app
   assets
        javascript
            controllers
            directives
            filters
            services
            vendor
        styles
        templates
            directives
    css
    images
    views
node_modules
server
    models
    routes

Don't ask me why there is a css and a styles folder...both of these store css files. 

So...the first thing I am going to do is create a new file in the directives folder called nwPageNav.js
This file is going to create the directive.

angular.module("MusicSchool").directive('nwPageNav', function(){
  return {
    replace: true,
    restrict: "E",
    templateUrl: "assets/templates/directives/nwPageNav.html",
    controller: function($scope, $location){
      $scope.isPage = function(name){
        return new RegExp("/" + name + "($|/)").test($location.path());
      };
    }
  };
});

The 'replace: true' specifies not to include the actual directive tag in the DOM when the directive is used. 
i.e.
<div>Stuff you put in directive</div> 
NOT 
<div><yourdirective>Stuff you put in directive</yourdirective></div>  

Why somebody would want 'replace:false' is beyond me. If I ever come across a situation where this is desired I will be sure to let everyone know.

The 'restrict: "E"' means the directive is only going to be used as an element and not an attribute.
i.e.
<likethis></likethis>    not     <div likethis></div>


Now in the templates/directives folder I am going to put the html for this directive:
<ul class="nav navbar-nav">
  <li ng-class="{'active': isPage('locker')}"><a href="#/locker">Locker</a></li>
  <li ng-class="{'active': isPage('classroom')}"><a href="#/classroom">Classroom</a></li>
  <li ng-class="{'active': isPage('community')}"><a href="#/community">Community Board</a></li>
</ul>

You'll notice that there is a isPage function being called on each link in the nav. This function was specified in my directives controller:
    controller: function($scope, $location){
      $scope.isPage = function(name){
        return new RegExp("/" + name + "($|/)").test($location.path());
      };
    }
It simply checks to see what page we are one and then highlights the nav link accordingly.

If you are on the locker page for example, that nav link will look different from the others...this is just a nice touch in my opinion.  It is using the ng-class directive, a built in angular directive which binds to the expression 'isPage(pagename)' which will be true or false depending on if you are on that page, and sets the class of the link to 'active'.  

If you don't know what data-binding is...you should really find out.  Its one of the greatest things I've ever seen so far in web development, and its something that only Angular does.  It allows variables to update instantaneously across the application, which will affect how the app looks.  The variables can be modified in the controllers and are automatically updated in the views.  This is called one-way data binding.  If you use models in your views (like for a form field entry for example) you can do two-way data binding. This is when an user input value is bound and can update the app instantaneously.  However don't get confused...this only works with ng-model bound variables...you cant just change something in the DOM of your view (like with jQuery) an expect it to data bind.

Now in my index.html (the main app page) I am going to put:
    <nav>
      <div class="container-fluid">
        <div class="navbar-header">
          <div class="navbar-brand">
            <a href="/#/">Music School Online</a>
          </div>
        </div>
        <nw-page-nav></nw-page-nav>
      </div>
    </nav>

The 'nw-page-nv' tag is the directive I just created, this is what is outputting my nav. The 'nav' tag is a HTML5 element which allows you to group together nav links, this will help screenreaders.  Its a new HTML5 thing, it doesnt do anything in particular except let everyone know where your navs are.  The css classes 'container-fluid', 'navbar-header', and 'navbar-brand' are simply css styles that I am using for my nav.  These are from the bootstrap.css.  You can get bootstrap from http://getbootstrap.com/css/ These are some common css properties that can really help with styling web development..in this case it makes my header nav responsive.  For example, this is what it looks like full screen:
And here is what it will look like on a small screen (a phone):
This responsiveness is a great feature.


Ok so that is it for the nav bar...stay tuned for the next episode.





No comments:

Post a Comment