0

Alright, I am fairly new to durandal. I am really struggling getting trying to accomplish this.

Here is what I am trying to do: There is a main navigation that is compromised of an inbox, draft, submitted, etc. Clicking on these, gives the user a submenu that comes out to the side of the main navigation. This submenu is generated by json data that I get from the server. Clicking an an option from the submenu should open the document in a viewer viewmodel based on the id of the document.

Ex.

User clicks on inbox 2. Menu comes out that has documents from their inbox. User clicks on view 3. Document that is clicked is displayed to the user. 4. So when they get to this point, I want the url to be mysite.com/#inbox/viewer/123456 (123456 is documentid)

I just haven't been able to find decent examples that are similar to this, and was wondering if someone could help point me in the right direction.

I kind of did it by making each main navigation link to a module, and have a document window in each of those modules, but I thought there had to be a better way. So what I am trying to do is keep my subnavigation in the shell. I don't want to have a module for each of my main navigation items.

Here is my shell code right now: shell.js

define(['durandal/system', 'services/logger', 'plugins/router', 'durandal/activator'], function (system, logger, router, activator) {


    //#region Internal Methods      

    function log(msg, data, showToast) {
        logger.log(msg, data, system.getModuleId(shell), showToast);
    }

    function logError(msg, data, showToast) {
        logger.logError(msg, data, system.getModuleId(shell), showToast);
    }


    function navigateRoute(hashValue) {
        var target = hashValue.hash;

        $("body").addClass("subnav-active");
        document.cookie = "subNav=true";

        $(target).addClass("current");
        router.navigate(target, {replace: true, trigger: false });

    }



    var routes = [
            { route: '', hash: '#home', moduleId: 'home', title: '', nav: false, cssClass: 'icon-inbox' },
            { route: 'inbox', hash: '#inbox', moduleId: 'inbox', title: 'Inbox', nav: true, cssClass: 'icon-inbox' },
            { route: 'drafts', hash: '#drafts', moduleId: 'drafts', title: 'Drafts', nav: true, cssClass: 'icon-file-alt' },
            { route: 'submitted', hash: '#submitted', moduleId: 'submitted', title: 'Submitted', nav: true, cssClass: 'icon-hand-right' },
            { route: 'completed', hash: '#completed', moduleId: 'completed', title: 'Completed', nav: true, cssClass: 'icon-check' },
            { route: 'settings', hash: '#settings', moduleId: 'settings', title: 'Settings', nav: true, cssClass: 'icon-cog' }
    ];
    //#endregion

    var shell = {
        activate: function () {
            router.on('router:route:not-found', function (fragment) {
                logError('No Route Found', fragment, true);
            });

            return router.makeRelative({ moduleId: 'viewmodels' }) // router will look here for viewmodels by convention
                .map(routes)            // Map the routes
                .buildNavigationModel() // Finds all nav routes and readies them
                .activate();            // Activate the router
        }
        ,
        router: router,
        navigateRoute: navigateRoute
    };
    return shell;
});

shell.html

<div class="main-wrapper wrapper">
<div class="container_template">
    <header class="pageheader">
        <nav class="mobile-nav">
            <a class="menu-button" href="#main-navigation">
                <i class="icon-reorder"></i><span>Menu</span>
            </a>
        </nav>

        <h1 class="logo">template</h1>
        <nav class="nav-user">
            <a class="close" href="#">
                <i class="icon-chevron-right"></i>
                <span>Main</span>
            </a>
        </nav>
    </header>

    <!-- Begin Header/Navigation -->
    <div class="main-navigation" role="banner">
        <div class="main-navigation-inner inner">
            <nav class="navigation">
                <ul data-bind="foreach: router.navigationModel">
                    <li>
                        <a class="nav-button" data-bind="attr: {'data-target': hash,}, css: {'nav-button' : isActive, active: isActive }, click: function(hash) { $root.navigateRoute(hash);return true},">
                            <i data-bind="css: cssClass"></i>
                            <span data-bind="html: title"></span>
                        </a>

                    </li>
                </ul>
            </nav>
        </div>
    </div>
    <!-- End Header/Navigation -->
    <!-- Sub Navigation Elements -->
    <!--This is my sbumenu-->
    <div id="inbox" class="navigation-sub">
        <div class="navigation-sub-inner inner">

            <div class="navigation-sub-header">
                <a class="close" href="#">&times;</a>
                <h3>Inbox</h3>
            </div>

            <div class="navigation-sub-search">
                <form>
                    <input type="text" placeholder="Search" />
                    <button>Go</button>
                </form>
            </div>
            <ul data-bind="contentsOfInbox">
                <li>
                    <a data-bind="href : linktoDocuemntViewer" href="" class="form-open">

                        <i class="icon-file-alt"></i><span data-bind="html: NameofDocumentHere"></span>
                        <span class="date" data-bind="html: DateOfDocumentHere"></span>
                    </a>
                </li>
            </ul>
        </div>
    </div>

    <!-- End SUB NAV -->
    <!--Begin Main-->
    <!--Documents would appear here-->
    <div class="main" data-bind=" router: { cacheViews: false }">


    </div>
    <!-- End Main -->
</div>

Thanks for any help

chuckw87
  • 647
  • 1
  • 6
  • 14

1 Answers1

0

For what you are trying to do it sounds like using the navigationModel will not work. From my experience, the navigationModel and route are a 1 to 1 relationship. What you are trying to do is have one route with parameters tied to multiple menu items. To do this you should separate your menus and routes. Remember at the heart of everything you are just binding javascript objects and collections to html elements. The router.navigationModel property is just that, a collection of javascript objects that is built from your defined routes. When you call .buildNavigationModel() that is what it is doing, building up a new collection of javascript objects for you to bind to your menu html. There is nothing stopping you from creating a completely new property on your shell viewmodel that contains your own custom collection of javascript menu objects and binding that to your UL/LI navigation html. If you make this new menu collection a computedObservable you could then add to it in a lazy fashion as you needed to and since it is bound with knockout, changes would appear in the UI automatically. I have done this on a number of different projects and it works fine. I build a menu table in the backend and then just return only the items that the user has access to and use that to build my UI menu. To make navigation work, I keep the urlhash in the table and bind that to the anchor tags. When you are creating routes, you don't have to set the hash property, the router plugin will take care of that for you. So for your requested example, create a menu collection like this:

    { displayname: 'Inbox' cssClass: 'icon-inbox', urlHash: '' children[
{ displayname: 'Doc 1' cssClass: 'icon-message', urlHash: 'inbox/viewer/12345' },
{ displayname: 'Doc 2' cssClass: 'icon-message', urlHash: 'inbox/viewer/12346' },
{ displayname: 'File 1' cssClass: 'icon-message', urlHash: 'inbox/viewer/12347' }]}

create a route like this:

{ route: 'inbox/viewer/:messageId', moduleId: 'home', title: '', nav: false, cssClass: 'icon-inbox' },

see the durandal docs for info on passing parameters to routes

expose this menu as a computedObesrvable from your shell and bind that to you UL/LI menu html instead of the router.NavigationModel. When needed, change the contents of the children property of the inbox menu with new data from the server.

Frank
  • 2,178
  • 2
  • 17
  • 24