2013-07-15 9 views
7

Ich habe gerade angefangen mit Durandal zu arbeiten und alle Teile passen zusammen und ich benutze die Hot Towel Vorlage, um die Dinge zu beschleunigen.Wie Dropdown-Menüs für Durandal-Navigation verwenden?

Eine Sache, die mich stumpft, ist, wie man ein komplizierteres hierarchisches Navigationssystem als eine Buttongroup schafft. Hier ist, was ich mit will am Ende:

ABC
A1 B1 C1
A2 B2 C2

A, B und C sind die Menüs der obersten Ebene, die keine Routen haben mit ihnen verbunden - sie sind einfach Platzhalter. Ich werde Views und Viewmodels für A1, A2, B1, B2, C1 und C2 haben und diese Hashtags als aktive Links benötigen.

Meine beste Idee ist im Moment, das Elternmenü in die URL jeder Route einzufügen und Code in nav.html zu haben, der dynamisch jeden Knoten auf der Basis der Analyse der URL zu dem entsprechenden Elternteil hinzufügt. Um vollständig dynamisch zu sein, würde es sowohl die Elternknoten als auch die Kindknoten dynamisch hinzufügen.

Ich habe eine Menge Suche nach hierarchischen Navigationsbeispielen mit Durandal gemacht, aber habe noch nichts gesehen. Gibt es eine Best Practice, um die Navigationsfunktionalität über die einfache eindimensionale Liste hinaus zu erweitern? Übersehen wir einige Funktionen im Router, die ich nicht sehen kann, ohne dass ich Hierarchieinformationen in die Ansichtsnamen einbetten muss?

EDIT: Ich habe gerade eine Antwort als richtig markiert, obwohl ich mit beiden Lösungen nicht zufrieden war. Wenn man ein Framework auswählt, um Logik, Präsentation und Kontrolle zu trennen und zu trennen, scheint es albern, diese Konstrukte wieder zusammenzuführen, um mehr als eine einfache Navigations-Shell bereitzustellen. Ich habe meine Entwicklungsbemühungen auf angularjs umgestellt, wo solche Dinge viel intuitiver werden und die Trennung beibehalten können. Hoffentlich kann Durandal in naher Zukunft ein wenig mehr voranschreiten und ich werde es definitiv für zukünftige Projekte neu bewerten.

Antwort

6

Sie könnten schwer Code sie in der Shell-Ansicht, aber wenn Sie nicht zu tun haben wollen, dass Sie es tun können -

Ihrer Meinung nach machen einen nicht funktionierenden Anker mit/#, das tut nichts, mit einem Drop-Down von A-Routen und einem anderen mit einem Drop-Down von B-Routen.

 <div class="nav-collapse collapse main-nav"> 
      <div class="btn-group"> 
       <a class="btn" href="/#"> 
        <span class="text">A Routes</span> </a> 
       <button class="btn dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button> 
        <ul class="dropdown-menu pull-right"> 
         <!-- ko foreach: aRoutes --> 
         <li data-bind="css: { active: isActive }"> 
          <a data-bind="attr: { href: hash }, html: name"></a> 
         </li> 
         <!-- /ko --> 
        </ul> 
      </div> 
      <div class="btn-group"> 
       <a class="btn" href="/#"> 
        <span class="text">B Routes</span> </a> 
       <button class="btn dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button> 
        <ul class="dropdown-menu pull-right"> 
         <!-- ko foreach: bRoutes --> 
         <li data-bind="css: { active: isActive }"> 
          <a data-bind="attr: { href: hash }, html: name"></a> 
         </li> 
         <!-- /ko --> 
        </ul> 
      </div> 
     </div> 

Machen Sie einige berechnete Observablen für die Routen in Ihrem Modell Shell-Ansicht

var aRoutes = ko.computed(function() { 
     return router.allRoutes().filter(function (r) { 
      return r.settings.aroute; 
     }); 
    }); 

    var bRoutes = ko.computed(function() { 
     return router.allRoutes().filter(function (r) { 
      return r.settings.broute; 
     }); 
    }); 

und in der Routendefinition -

{ 
    url: 'a1', 
    moduleId: 'viewmodels/a1', 
    name: 'A1', 
    visible: false, 
    settings: {aroute: true} 
}, 

Diese alle Routen auf false setzt, und dann gibt sie ein anderes Attribut von aurte, das auf wahr gesetzt wird. Die berechnete Filterung führt nur zu Routen, bei denen diese Einstellung auf "True" gesetzt ist.

+0

Dies ist eine ausgezeichnete Idee - markieren Sie die Route mit ihren Eltern. Ich werde daran ein wenig arbeiten, um es dynamischer zu machen, und vielleicht sogar als Durandal-Widget. – Graham

+0

Hoffe es hilft dir, ich benutze diese Methode seit einer Weile und es funktioniert sehr gut und ist gleichzeitig dynamisch. Ich habe gerade gesehen, dass ich nicht die richtige Einrückung auf den b Routen hatte, also habe ich das gerade repariert. Viel Glück. –

3

Ich habe eine allgemeine Lösung entwickelt, nachdem ich diesen Beitrag gelesen habe. Mit dieser Lösung können Sie dynamisch Routen zu einem Dropdown-Menü im Nav hinzufügen.

In main.js, wo ich meine Routen spezifiziere, habe ich eine Funktion hinzugefügt, um das Untermenüobjekt dem Einstellungsobjekt der Hauptnavigationsroute zuzuordnen.

function mapSubNav(parentRouteInfo) { 
    var subroutes = []; 
    var length = arguments.length; 
    for (var i = 0; i < length; i++) { 
     subroutes.push(arguments[i]); 
    } 
    parentRouteInfo.settings.subroutes = subroutes; 
} 

var page = router.mapNav('page', null, 'Page'), 
    sub1 = router.mapRoute('page/sub1', null, 'Sub1'), 
    sub2 = router.mapRoute('page/sub2', null, 'Sub2'); 
mapSubNav(nav, sub1, sub2); 

Erläuterung:

Die Router-Funktion mapNav eine Route Definition gibt, die wie folgt aussieht:

{ 
    url:'flickr', //you provided this 
    name: 'Flickr', //derived 
    moduleId: 'flickr', //derived 
    caption: 'Flickr', //derived (uses to set the document title) 
    settings: {}, //default, 
    hash: '#/flickr', //calculated 
    visible: true, //from calling mapNav instead of mapRoute 
    isActive: ko.computed //only present on visible routes to track if they are active in the nav 
} 

Die Hilfsfunktion, mapSubNav, wird eine Liste von Referenzen platzieren zu den Routen, die im Dropdown-Menü im Einstellungsobjekt angezeigt werden sollen. In diesem Beispiel wird das Ergebnis sein:

{ 
    url:'page', 
    name: 'Page', 
    moduleId: 'page', 
    caption: 'Page', 
    settings: { subroutes: [nav, sub1, sub2] }, 
    hash: '#/page', 
    visible: true, 
    isActive: ko.computed 
} 

Ich streckte meine Schale Ansichtsmodell wie folgt aussehen:

define(function (require) { 
    var router = require('durandal/plugins/router'); 
    var app = require('durandal/app'); 

    var ViewModel = function() { 
     var self = this; 
     self.router = router; 
     self.dataToggle = function (route) { 
      return !!route.settings.subroutes ? 'dropdown' : ''; 
     }; 
     self.html = function (route) { 
      return !!route.settings.subroutes ? route.name + ' <b class="caret"></b>' : route.name; 
     }; 
     self.hash = function (route) { 
      return !!route.settings.subroutes ? '#' : route.hash; 
     }; 
     self.divider = function (route, parent) { 
      system.log('Adding', route, 'to dropdown', 'Parent', parent); 
      return route.hash === parent.hash; 
     }; 
     self.activate = function() { 
      return router.activate('welcome'); 
     } 
    }; 

    return new ViewModel(); 
}); 

Hinweis:

die Zusatzfunktionen In shell.js wird entscheiden, welche Attribute hinzugefügt werden sollen die DOM-Elemente im Nav.


Und schließlich habe ich meine Shell-Ansicht bearbeitet, um so zu sehen;

<div class="nav-collapse collapse"> 
    <ul class="nav navbar-nav" data-bind="foreach: router.visibleRoutes()"> 
     <li data-bind="css: { active: isActive, dropdown: !!settings.subroutes }"> 
      <a data-bind="css: { 'dropdown-toggle': !!settings.subroutes }, 
          attr: { href: $root.hash($data), 'data-toggle': $root.dataToggle($data) }, 
          html: $root.html($data)"></a> 
      <ul data-bind="foreach: settings.subroutes" class="dropdown-menu"> 
       <li><a data-bind="attr: { href: hash }, 
            html: name"></a></li> 
       <li data-bind="css: { divider: $root.divider($data, $parent) }"></li> 
      </ul> 
     </li> 
    </ul> 
</div> 

Ergebnis:

Das Endergebnis ist ein Menüpunkt mit einem Drop-Down-Schalter. Das Dropdown-Menü enthält einen Link zum übergeordneten und jeweils einen Link zu den Unterrouten. Etwas wie folgt aus:

--------------------------------------------- 
Menu items... | Page v | More menu items... 
--------------------------------------------- 
       | Page | 
       ---------- 
       | Sub 1 | 
       | Sub 2 | 
       ---------- 

jQuery Sie eine Route zu einem Drop-Down-Umschalt-Schaltfläche Karte nicht lassen, weshalb ich die Eltern-Route einen Verweis auf sich selbst in der Liste der SubRoutes Es gibt noch halten gemacht werden gibt es eine Link zur übergeordneten Route im Nav.

+0

Was ist anders als die Antwort, die ich zur Verfügung gestellt habe? –

+0

@PWKad Mit meiner Lösung, sobald alles eingerichtet ist, können Sie weiterhin "mapSubNav" in main.js verwenden, und die Untermenüs werden automatisch hinzugefügt, ohne dass andere Dateien bearbeitet werden müssen. Ich habe nicht gesehen, wie das mit Ihrer Lösung erreicht werden kann. Habe ich etwas vergessen? –