Igor Simic
6 years ago

Angular Priority navigation using Material Design


Priority or Greedy navigation is a really nice way to show long navigation items on small screens. The idea is that navigation element is moved to drop-down selection menu when there is not enough space on the screen.

In this example we will create directive and we will use Angular Material Design Google library to achieve it and putting everything in nice Priority nav directive.

Tutorial Greedy navigation using Angular 7 and Material Design you can find here: https://www.coditty.com/code/greedy-navigation-using-angular-7-and-material-design


So let's first create HTML element
<nav flex="70" prionav  hide-all-width="250" id="matang-top-navigation">
    <div layout="row" class="prionav">
            <md-button ng-repeat="menuItem in matang_menu_header" id="matang-header-nav-{{menuItem.ID}}" data-mid="{{menuItem.ID}}" href="{{menuItem.slug}}">{{menuItem.title}}</md-button>
        </div>

</nav>
  • hide-all-width is width in pixels where all element will be moved to drop down element (for small screens)
  • prionav is directive name

OK, let's set up needed CSS:
#matang-top-navigation{ 	
	overflow: hidden;
    border: 0px solid white;
    position: relative;
}
 

.prionav{
	width: 1000px;
}

and now finally let's create directive:
app.directive('prionav',['$rootScope',function($rootScope){

	return {
		restrict:"A,E", 
		link:function(scope,element,attrs){
				
		        $rootScope.showPrioNavDrop = false;

		        var recalcItemElementPosition= function(element,atts){

             	        var movedObjects = [];
					
		        // loop over all elements
                	for (var i = 0; i < element[0].children[0].children.length; i++) {


                		// if element is out of nav block or element width is less than added in atribute hide-all-width
						if( element[0].children[0].children[i].offsetLeft + element[0].children[0].children[i].offsetWidth > element[0].offsetWidth || element[0].offsetWidth < atts.hideAllWidth ){

							document.getElementById(element[0].children[0].children[i].id).style.visibility = 'hidden';
 
							$rootScope.showPrioNavDrop = true; 

							// loop top menu root items
							for (var iel = 0; iel < appInfo.matang_menu_header.length; iel++) {
							 
								// select matching element by id
								if(element[0].children[0].children[i].dataset.mid == appInfo.matang_menu_header[iel].ID){

									movedObjects.push(appInfo.matang_menu_header[iel]);
										
									} 
							}
							 
							
						}else{
 							document.getElementById(element[0].children[0].children[i].id).style.visibility = 'visible';
 						 
							}

                	}

                	scope.$apply(function(){
				           scope.prionavElements = movedObjects; 
				      });


                	if(movedObjects.length < 1){
                		$rootScope.showPrioNavDrop = false; 
                	}

                	  
			}

			setTimeout(function() {

 				// call func on load
 					recalcItemElementPosition(element,attrs);
				
			}, 0);

					
			window.onresize = function(event) {

					// call func on resize
				recalcItemElementPosition(element,attrs);
			}





		}
	};

}]);

and then finally we will create drop down button which could be placed next to prionav element
<div flex layout="row" layout-align="end center">

	<md-menu>
		<md-button ng-show="showPrioNavDrop" aria-label="Open menu with custom trigger" class="md-icon-button" ng-click="$mdMenu.open()"><!-- ng-mouseenter="$mdMenu.open()" -->
			<md-icon md-menu-origin md-svg-icon="arrow-down-drop-circle-outline"></md-icon>
		</md-button>
		
		<md-menu-content  ><!--  ng-mouseleave="$mdMenu.close()" -->
			<md-menu-item ng-repeat="item in prionavElements">
				<md-button href="{{item.slug}}">{{item.title}}</md-button>
			</md-menu-item>
		</md-menu-content>
		
	</md-menu>
</div>

and that is it :)