2015-08-20 8 views
5

Ich lerne immer noch Angular und habe begonnen, eine einfache Website zu erstellen. Ich habe Routing und einige Logik aus meiner Sicht, eine aktive Klasse auf dem Menüpunkt zu haben, wenn die URL auf dieser Seite ist. Das Problem, das ich beginne zu sehen, ist, wenn ich die URL von/nach/nach Hause ändere, muss ich es im Routing und in der Ansicht und auch in der Logik aktualisieren, um zu sehen, ob es aktiv sein sollte.

Ich frage mich, gibt es einen besseren Weg, dies zu tun, um es trocken zu machen?

Meine app.js Datei sieht wie folgt 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 meines index.html sieht wie folgt 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 man sehen kann ich die isActive Methode aufrufen, auf der Nav-Controller, aber ich muss immer sicherstellen, dass die URL, die ich übergebe, korrekt ist.

das ist mein nav-Controller:

angular.module('simpleApp') 
    .controller('NavController', function($scope, $location) { 
    this.isActive = function (url) { 
     return url === $location.path(); 
    }; 
    }); 
+0

mögliche Duplikate von [Set aktive Registerkarte Stil mit AngularJS] (http://StackOverflow.com/Questions/12295983/Set-Active-Tab-Style-With-angularjs) –

+0

Ich glaube nicht, dass es ein Duplikat wie die Frage wurde beantwortet mit wie ich meinen Code schon geschrieben habe. Meine Frage ist, wie man es trocken macht. Alles, sei es eine der Antworten ist eine benutzerdefinierte Anweisung zu verwenden, so wird es sich anschauen. Vielen Dank, dass Sie mich darauf aufmerksam gemacht haben, weil ich nicht wusste, was ich hier googlen/suchen sollte, um sicherzugehen, dass ich nichts vervielfältige. – saunders

+0

Ich zeigte auf die akzeptierte Antwort, die der beste Weg ist. Erfordert keine zusätzlichen Anweisungen oder Methoden. Sie fügen Ihrer Route einfach ein benutzerdefiniertes Attribut hinzu wie '.when ('/', { templateUrl: 'views/home/index.html', activetab: 'home' })' und dann in Ihrem html this '

  • ' –

    Antwort

    0

    Ich fand schließlich heraus, was ich von der möglichen doppelten Frage tun musste, aber änderte es leicht, um mit der '/' URL zu arbeiten.

    Das ist mein 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> 
    

    dies mein app.js ist:

    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 mein navdirective Datei:

    diese
    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'); 
          } 
         }); 
         } 
        }; 
        }); 
    

    zu verwenden, fügte ich hinzu detect-active-tab="1" an meine a-Tag und dann die Richtlinie zu meinem Index.html

    Ich habe auch einen Blick in ui Router und es hat die Dinge viel einfacher gemacht, da das Routing ist sehr ähnlich, wie ngRoute eingerichtet ist, aber alles, was Sie tun, ist ui-sref="/services" zu meinen Links hinzufügen und ui-sref-active="active" zu meinen li und es Arbeitet für mich den aktiven Zustand aus, der ganz nett ist.

    +0

    aktualisieren. Ich sehe nicht, dass Ihr Code überhaupt verbessert wurde.Anstatt ein paar Zeichen sofort lesbaren Codes zu haben, hast du ein haariges Monster mit einer Funktion, die für ihren einfachen Zweck viel zu kompliziert ist. Es ist Ihnen nur gelungen, Ihren Code weniger lesbar und wartbar zu machen. Wenn Sie etwas tun werden, um die Duplizierung zu reduzieren, ändern Sie Ihre gesamte Navigationsleiste in eine 'ng-Wiederholung', basierend auf einem Array von Objekten. – Jan

    +0

    Das war die Antwort auf mein Problem, das ich zuerst gestellt habe. Ich änderte es auf ui Route, wie ich unten sagte, was bedeutet, dass ich die Direktive loswerde und es viel einfacher zu lesen ist. – saunders

    +0

    Ich bin mir nicht sicher, ob du 10 Mal mehr Code hinzufügen solltest und komplexer als das, was du getan hast, sollte die Antwort auf alles sein ... – Jan

    0

    Schauen Sie sich die ng-Klasse-Richtlinie.

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

    Grundsätzlich würden Sie eine ng-Klasse Bezug auf Ihre Menüpunkte haben, die die Expression Teil verwendet den Menüpunkt zum aktiven Element zu vergleichen und dann, wenn dieser Ausdruck true ergibt, wird die Klasse auf diesen Gegenstand angewendet.

    +1

    ist das nicht genau das, was ich schon mache? – saunders

    +0

    Ja, nicht sicher, wie ich das vorher verpasst habe. Ich werde unten eine bessere Antwort hinzufügen. –

    +0

    Okay, keine Sorgen. Wurde deine zweite Antwort unterbrochen? – saunders

    0

    Dies wäre ein guter Platz für eine benutzerdefinierte Richtlinie. Die Direktive könnte den HTML-Code so darstellen, wie er oben ist, aber der tatsächliche HTML-Code in Ihrem Dokument würde ungefähr so ​​aussehen: <myNav url='about'>.

    +0

    Ich habe meine Frage bearbeitet, um eine Direktive zu verwenden, aber weil ich/als meine Homepage verwende, wird der Home Link nicht aktiviert. irgendwelche Ideen? – saunders

    +0

    Das ist ziemlich beeindruckende Arbeit dort. Ich glaube, du musst nur innerhalb des Codes nach dem leeren Pfad suchen und wenn es gefunden wird, setze die Klasse auf den Home-Link. Sie könnten Ihrer Anweisung wahrscheinlich einen optionalen Parameter hinzufügen, den Sie nur auf den Home-Link setzen, um anzuzeigen, dass er die aktive Klasse erhält, wenn die URL einfach/ist. –

    +0

    Danke, ich habe es am Ende herausgefunden, bin aber zum UI-Router umgezogen, was das alles für mich tut. – saunders

    1

    Wenn Sie sich nicht wiederholen wollen, warum nicht einfach eine ng-repeat verwenden?

    <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, nicht zu wiederholen, warum es existiert. Also wiederholst du dich nicht. ng-repeat ist wirklich wirklich gut für die Fälle, wenn Sie sich nicht wiederholen wollen. Wenn Sie vermeiden möchten, sich zu wiederholen, würde ich vorschlagen, dass Sie es verwenden.Und mit "it" meine ich ng-repeat. Um Wiederholungen zu vermeiden.

    +0

    Das ist eigentlich eine schöne Idee. Ich habe es mit einem Router repariert, aber das ist auch eine gute Methode und schön zu wissen. – saunders

    +0

    @ Jan Hallo, ich habe einen Zweifel. Dieser Code ruft die Funktion navCtrl.isActive für alle Elemente auf. Nehmen wir an, ich habe 50 Elemente in navbarLinks, dann wird die isActive-Funktion 50 Elemente aufgerufen. Ist das elegant? – overlord

    +0

    @overlord Nun, es kommt darauf an. Was wäre die Alternative, eine Eigenschaft für jedes Navigationselement festzulegen? Dann müsste diese Eigenschaft überall aktualisiert werden, wo sich die Route ändern könnte. Wäre das elegant? Es hängt vom Rest des Codes ab. – Jan

    0

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

    meine app.js Datei sieht wie folgt nun:

    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 meine html sieht wie folgt 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> 
    

    Alles, was ich tun musste, war der Hinweis auf UI-Router in meinem Index hinzufügen .html und ändern Sie die Konfiguration gemäß der Dokumentation für den UI-Router. Dann fügte ui-sref und ui-sref-active="active" der li hinzu, um es aktiv zu machen, und der Zauber des UI-Routers tat den Rest.