function MdNavItem($mdAria, $$rAF, $mdUtil, $window) {
  return {
    restrict: 'E',
    require: ['mdNavItem', '^mdNavBar'],
    controller: MdNavItemController,
    bindToController: true,
    controllerAs: 'ctrl',
    replace: true,
    transclude: true,
    template: function(tElement, tAttrs) {
      var hasNavClick = tAttrs.mdNavClick;
      var hasNavHref = tAttrs.mdNavHref;
      var hasNavSref = tAttrs.mdNavSref;
      var hasSrefOpts = tAttrs.srefOpts;
      var navigationAttribute;
      var navigationOptions;
      var buttonTemplate;

      // Cannot specify more than one nav attribute
      if ((hasNavClick ? 1 : 0) + (hasNavHref ? 1 : 0) + (hasNavSref ? 1 : 0) > 1) {
        throw Error(
          'Please do not specify more than one of the md-nav-click, md-nav-href, ' +
          'or md-nav-sref attributes per nav-item directive.'
        );
      }

      if (hasNavClick !== undefined && hasNavClick !== null) {
        navigationAttribute = 'ng-click="ctrl.mdNavClick()"';
      } else if (hasNavHref !== undefined && hasNavHref !== null) {
        navigationAttribute = 'ng-href="{{ctrl.mdNavHref}}"';
      } else if (hasNavSref !== undefined && hasNavSref !== null) {
        navigationAttribute = 'ui-sref="{{ctrl.mdNavSref}}"';
      } else {
        throw Error(
          'Please specify at least one of the md-nav-click, md-nav-href, or md-nav-sref ' +
          'attributes per nav-item directive.');
      }

      navigationOptions = hasSrefOpts ? 'ui-sref-opts="{{ctrl.srefOpts}}" ' : '';

      if (navigationAttribute) {
        buttonTemplate = '' +
          '<md-button class="_md-nav-button md-accent" ' +
            'ng-class="ctrl.getNgClassMap()" ' +
            'ng-blur="ctrl.setFocused(false)" ' +
            'ng-disabled="ctrl.disabled" ' +
            'tabindex="-1" ' +
            'role="tab" ' +
            'ng-attr-aria-label="{{ctrl.navItemAriaLabel ? ctrl.navItemAriaLabel : undefined}}" ' +
            'aria-selected="{{ctrl.isSelected()}}" ' +
            navigationOptions +
            navigationAttribute + '>' +
            '<span ng-transclude class="_md-nav-button-text"></span>' +
          '</md-button>';
      }

      return '' +
        '<li class="md-nav-item" ' +
          'role="presentation">' +
          (buttonTemplate || '') +
        '</li>';
    },
    scope: {
      'mdNavClick': '&?',
      'mdNavHref': '@?',
      'mdNavSref': '@?',
      'srefOpts': '=?',
      'name': '@',
      'navItemAriaLabel': '@?',
    },
    link: function(scope, element, attrs, controllers) {
      var disconnect;
      var mdNavItem;
      var mdNavBar;
      var navButton;

      // When accessing the element's contents synchronously, they
      // may not be defined yet because of transclusion. There is a higher
      // chance that it will be accessible if we wait one frame.
      $$rAF(function() {
        mdNavItem = controllers[0];
        mdNavBar = controllers[1];
        navButton = angular.element(element[0].querySelector('._md-nav-button'));

        if (!mdNavItem.name) {
          mdNavItem.name = angular.element(element[0]
              .querySelector('._md-nav-button-text')).text().trim();
        }

        navButton.on('keydown', function($event) {
          mdNavBar.onKeydown($event);
        });

        navButton.on('focus', function() {
          mdNavItem._focused = true;
        });

        navButton.on('click', function() {
          // This triggers a watcher on mdNavBar.mdSelectedNavItem which calls
          // MdNavBarController._updateTabs() after a $timeout. That function calls
          // MdNavItemController.setSelected() for the old tab with false and the new tab with true.
          mdNavBar.mdSelectedNavItem = mdNavItem.name;
          scope.$apply();
        });

        // Get the disabled attribute value first, then setup observing of value changes
        mdNavItem.disabled = $mdUtil.parseAttributeBoolean(attrs['disabled'], false);
        if ('MutationObserver' in $window) {
          var config = {attributes: true, attributeFilter: ['disabled']};
          var targetNode = element[0];
          var mutationCallback = function(mutationList) {
            $mdUtil.nextTick(function() {
              mdNavItem.disabled = $mdUtil.parseAttributeBoolean(attrs[mutationList[0].attributeName], false);
            });
          };
          var observer = new MutationObserver(mutationCallback);
          observer.observe(targetNode, config);
          disconnect = observer.disconnect.bind(observer);
        } else {
          attrs.$observe('disabled', function (value) {
            mdNavItem.disabled = $mdUtil.parseAttributeBoolean(value, false);
          });
        }

        if (!mdNavItem.navItemAriaLabel) {
          $mdAria.expectWithText(navButton, 'aria-label');
        }
      });

      scope.$on('destroy', function() {
        navButton.off('keydown');
        navButton.off('focus');
        navButton.off('click');
        disconnect();
      });
    }
  };
}
@param $mdAria
@param $$rAF
@param $mdUtil
@param $window
@constructor
@ngInject