Ich lerne immer noch Angular und habe begonnen, eine einfache Website zu erstellen. Ich habe Routing und eine Logik in meiner Ansicht, um eine aktive Klasse im Menüelement zu haben, wenn sich die URL auf dieser Seite befindet. Das Problem, das ich zu sehen beginne, ist, wenn ich die URL von / nach / home ändere, muss ich sie im Routing und in der Ansicht sowie in der Logik aktualisieren, um zu sehen, ob sie aktiv sein sollte.

Ich habe mich gefragt, ob es einen besseren Weg gibt, dies trocken zu machen.

Meine app.js-Datei sieht folgendermaßen aus:

    angular.module('simpleApp', ['ngRoute'])
  .config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
    $routeProvider
      .when('/', {
        templateUrl: 'views/home/index.html'
      })
      .when('/about', {
        templateUrl: 'views/about/index.html',
        controller: 'AboutController',
        controllerAs: 'aboutCtrl'
      })
      .when('/services', {
        templateUrl: 'views/services/index.html',
        controller: 'ServicesController',
        controllerAs: 'servicesCtrl'
      })
      .when('/contact', {
        templateUrl: 'views/contact/index.html',
        controller: 'ContactController',
        controllerAs: 'contactCtrl'
      })
      .otherwise({
        redirectTo: '/'
      });
  }]);

Und Teilansicht meiner index.html sieht so aus:

<nav class="navbar navbar-inverse" ng-controller="NavController as navCtrl">
          <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
              <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
              </button>
              <a class="navbar-brand" href="/#/">SimpleApp</a>
            </div>
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
              <ul class="nav navbar-nav">
                <li ng-class="{ 'active': navCtrl.isActive('/')}">
                  <a href="/#/">Home</a>
                </li>
                <li ng-class="{ 'active': navCtrl.isActive('/about')}">
                  <a href="/#/about">About</a>
                </li>
                <li ng-class="{ 'active': navCtrl.isActive('/services')}">
                  <a href="/#/services">Services</a>
                </li>
                <li ng-class="{ 'active': navCtrl.isActive('/contact')}">
                  <a href="/#/contact">Contact Us</a>
                </li>
              </ul>
            </div>
          </div>
        </nav>

Wie Sie sehen, rufe ich die isActive-Methode auf dem Navigationscontroller auf, muss aber immer sicherstellen, dass die von mir übergebene URL korrekt ist.

Das ist mein Navigations-Controller:

    angular.module('simpleApp')
  .controller('NavController', function($scope, $location) {
    this.isActive = function (url) {
      return url === $location.path();
    };
  });
5
saunders 20 Aug. 2015 im 20:55

5 Antworten

Beste Antwort

Ich habe schließlich anhand der möglichen doppelten Frage herausgefunden, was ich tun muss, aber es leicht geändert, um mit der '/' URL zu arbeiten.

Das ist meine index.html

<!DOCTYPE html>
<html>
<head>
  <title>Simple Angular App</title>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
  <link rel="stylesheet" type="text/css" href="css/styles.css">
</head>
  <body ng-app="simpleApp">
    <header>
      <div class="container">
        <nav class="navbar navbar-inverse">
          <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
              <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
              </button>
              <a class="navbar-brand" href="/#/">SimpleApp</a>
            </div>
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
              <ul class="nav navbar-nav">
                <li>
                  <a href="#/" detect-active-tab="1">Home</a>
                </li>
                <li>
                  <a href="#/about" detect-active-tab="1">About</a>
                </li>
                <li>
                  <a href="#/services" detect-active-tab="1">Services</a>
                </li>
                <li>
                  <a href="#/contact" detect-active-tab="1">Contact Us</a>
                </li>
              </ul>
            </div>
          </div>
        </nav>
      </div>
    </header>
    <main>
      <div class="container">
        <div class="row">
          <div ng-view></div>
        </div>
      </div>
    </main>
    <footer>
      <div class="container">
        <div class="row">
          <div class="col-xs-12">
            <p class="footer-text">First attempt at an AngularJs site</p>
          </div>
        </div>
      </div>
    </div>
  </footer>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/js/bootstrap.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js"></script>
    <script src="https://code.angularjs.org/1.4.4/angular-route.min.js"></script>

    <script src="js/app.js"></script>

    <script src="js/directives/shared/navdirective.js"></script>

    <script src="js/controllers/contact/ContactController.js"></script>
    <script src="js/controllers/about/AboutController.js"></script>
    <script src="js/controllers/services/ServicesController.js"></script>
  </body>
</html>

Das ist meine app.js:

angular.module('simpleApp', ['ngRoute'])
  .config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
    $routeProvider
      .when('/', {
        templateUrl: 'views/home/index.html'
      })
      .when('/about', {
        templateUrl: 'views/about/index.html',
        controller: 'AboutController',
        controllerAs: 'aboutCtrl'
      })
      .when('/services', {
        templateUrl: 'views/services/index.html',
        controller: 'ServicesController',
        controllerAs: 'servicesCtrl'
      })
      .when('/contact', {
        templateUrl: 'views/contact/index.html',
        controller: 'ContactController',
        controllerAs: 'contactCtrl'
      })
      .otherwise({
        redirectTo: '/'
      });

      // if(window.history && window.history.pushState) {
      //   $locationProvider.html5Mode({
      //     enabled: true,
      //     requireBase: false
      //   });
      // }
  }]);

Und das ist meine navdirective Datei:

angular.module('simpleApp')
  .directive('detectActiveTab', function ($location) {
    return {
      restrict: 'A',
      link: function postLink(scope, element, attrs) {
        scope.$on("$routeChangeSuccess", function (event, current, previous) {
            // This var grabs the tab-level off the attribute, or defaults to 1
            var pathLevel = attrs.detectActiveTab || 1;

            if($location.path() === '/') {
              var pathToCheck = $location.path() ||
                  "current $location.path doesn't reach this level";
              var tabLink = attrs.href.split('#')[pathLevel] ||
                  "href doesn't include this level";
            } else {
              var pathToCheck = $location.path().split('/')[pathLevel] ||
                  "current $location.path doesn't reach this level";
                  // This var finds grabs the same level of the href attribute
              var tabLink = attrs.href.split('/')[pathLevel] ||
                  "href doesn't include this level";
            }

            if (pathToCheck === tabLink) {
              element.parent('li').addClass('active');
            }
            else {
              element.parent('li').removeClass('active');
            }
        });
      }
    };
  });

Um dies zu verwenden, habe ich detect-active-tab="1" zu meinem a-Tag hinzugefügt und dann die Direktive in meine index.html aufgenommen

Ich habe mir auch den UI-Router angesehen und es hat die Dinge viel einfacher gemacht, da das Routing sehr ähnlich wie ngRoute eingerichtet ist, aber alles, was Sie tun, ist, ui-sref="/services" zu meinen Links und ui-sref-active="active" hinzuzufügen zu meinen li's und es klappt der aktive zustand für mich was ganz nett ist.

0
saunders 20 Aug. 2015 im 20:49

Überprüfen Sie die ng-class-Direktive.

https://docs.angularjs.org/api/ng/directive/ngClass

Grundsätzlich hätten Sie eine ng-Klassenreferenz für Ihre Menüelemente, die den Ausdrucksteil verwendet, um das Menüelement mit dem aktiven Element zu vergleichen. Wenn dieser Ausdruck dann als wahr ausgewertet wird, wird die Klasse auf dieses Element angewendet.

0
Mike Feltman 20 Aug. 2015 im 17:59

Dies wäre ein guter Ort für eine benutzerdefinierte Richtlinie. Die Direktive könnte das HTML so rendern, wie es oben ist, aber das tatsächliche HTML in Ihrem Dokument würde ungefähr so aussehen wie <myNav url='about'>.

0
Mike Feltman 20 Aug. 2015 im 20:31

Obwohl meine erste Antwort meine ursprüngliche Frage gelöst hat. Es gab mir andere Probleme, da es sehr komplex und schwer zu warten war. Ich entschied mich für einen UI-Router, was die Sache viel einfacher machte.

Meine Datei app.js sieht jetzt so aus:

angular.module('simpleApp', ['ui.router'])
  .config(function ($stateProvider, $urlRouterProvider) {
    $urlRouterProvider.otherwise('/');

    $stateProvider
      .state('/', {
        url: '/',
        templateUrl: 'views/home/index.html'
      })
      .state('/about', {
        url: '/about',
        templateUrl: 'views/about/index.html',
        controller: 'AboutController',
        controllerAs: 'aboutCtrl'
      })
      .state('/services', {
        url: '/services',
        templateUrl: 'views/services/index.html',
        controller: 'ServicesController',
        controllerAs: 'servicesCtrl'
      })
      .state('/contact', {
        url: '/contact',
        templateUrl: 'views/contact/index.html',
        controller: 'ContactController',
        controllerAs: 'contactCtrl'
      });
  });

Und mein HTML sieht so aus:

    <!DOCTYPE html>
<html>
<head>
  <title>Simple Angular App</title>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
  <link rel="stylesheet" type="text/css" href="css/styles.css">
</head>
  <body ng-app="simpleApp">
    <header>
      <div class="container">
        <nav class="navbar navbar-inverse">
          <div class="container-fluid">
            <!-- Brand and toggle get grouped for better mobile display -->
            <div class="navbar-header">
              <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
              </button>
              <a class="navbar-brand" href="/#/">SimpleApp</a>
            </div>
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
              <ul class="nav navbar-nav">
                <li ui-sref-active="active">
                  <a ui-sref="/">Home</a>
                </li>
                <li ui-sref-active="active">
                  <a ui-sref="/about">About</a>
                </li>
                <li ui-sref-active="active">
                  <a ui-sref="/services">Services</a>
                </li>
                <li ui-sref-active="active">
                  <a ui-sref="/contact">Contact Us</a>
                </li>
              </ul>
            </div>
          </div>
        </nav>
      </div>
    </header>
    <main>
      <div class="container">
        <div class="row">
          <div ui-view></div>
        </div>
      </div>
    </main>
    <footer>
      <div class="container">
        <div class="row">
          <div class="col-xs-12">
            <p class="footer-text">First attempt at an AngularJs site</p>
          </div>
        </div>
      </div>
    </div>
  </footer>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/js/bootstrap.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js"></script>
    <script src="js/lib/angular-ui-router.min.js"></script>

    <script src="js/app.js"></script>

    <script src="js/controllers/contact/ContactController.js"></script>
    <script src="js/controllers/about/AboutController.js"></script>
    <script src="js/controllers/services/ServicesController.js"></script>
  </body>
</html>

Ich musste lediglich den Verweis auf den UI-Router in meine index.html einfügen und die Konfiguration gemäß der Dokumentation für den UI-Router ändern. Fügen Sie dann ui-sref und ui-sref-active="active" zum li hinzu, um es zu aktivieren, und die Magie des UI-Routers erledigte den Rest.

0
saunders 21 Aug. 2015 im 17:56

Wenn Sie sich nicht wiederholen möchten, verwenden Sie einfach ein ng-repeat.

<ul class="nav navbar-nav">
  <li ng-repeat="item in navbarLinks" ng-class="{ 'active': navCtrl.isActive(item.link)}">
     <a href="/#{{item.link}}">{{item.text}}</a>
  </li>
</ul>

Ich meine, sich nicht wiederholen zu müssen, ist der Grund, warum es existiert. Sie wiederholen sich also nicht. ng-repeat ist wirklich gut für Fälle, in denen Sie sich nicht wiederholen möchten. Wenn Sie vermeiden möchten, sich zu wiederholen, würde ich empfehlen, dass Sie es verwenden. Und mit "es" meine ich ng-repeat. Um Wiederholungen zu vermeiden.

1
Jan 20 Aug. 2015 im 22:22