0
votes

I'm attempting to use the following structure to implement navigation buttons using ko (2.3.0), requirejs (2.1.9) and durandal (2.0.1):

file named index.cshtml includes: div named applicationHost which loads: shell.html which includes: div to contain header.html, which includes: div to contain data.html, which displays summary info relative to the logged-in user div to contain nav.html which includes: all the links for navigation. div to contain all other views, depending on which route is active

The router is bound to the shell.html (via shell.js), using boilerplate code to create the router:

var shell = {
            router: router,
            activate: function () {                    
                router.map(config.routesNLI).buildNavigationModel();
                return router.activate(my.viewToDisplay());
            }
};
return shell;

and is bound in shell.html using the standard:

<div>
    <!-- ko compose: {model: router.activeItem, afterCompose: router.afterCompose } -->
    <!-- /ko -->
</div>

I took out the transition: 'entrance' because I read where that was causing some people problems, but it had no affect in my case.

The config.routesNLI consists of entries using this pattern:

{
    route: 'NLIincontext',
    title: 'In Context',
    moduleId: 'viewmodels/NLIincontext',
    hash: '#/NLIincontext',
    nav: true
}

My html for loading the nav.html element into shell.html is:

<div>
    <!-- ko compose: {view: 'nav' } -->
    <!-- /ko -->
</div>

This is based on the pattern used by John Papa in his excellent PluralSight course , 'Single Page Apps JumpStart'.

When the app is run, the display appears correct, and when you hover on a nav link button, you see (as an example):

localhost:49690/index.cshtml#/NLIincontext

When you click one of the nav buttons, the address bar is changed to:

http://localhost:49690/index.cshtml#/NLIincontext

No other visible change is seen on the page, however. If you click at the end of the link in the address bar and click enter, the page loads the appropriate view into the div used in shell.html to display the active item of the router.

Also, if you refresh the page, the address in the address bar does not change, but the page will, upon refresh, display the data associated with the address in the address bar.

No activity is shown in the console log window, even though system.debug(true) is included in my main.js file, and no network activity is displayed when I click the button, nor regardless of how many times the button is clicked.

I have tried data-binding to the div in shell.html using various scenarios, such as:

<div data-bind="compose: { view: 'nav' }"></div>

I've even bound the nav.html element to the viewmodel (nav.js) by returning the router from nav.js and using this type of binding in shell.html:

<div data-bind="compose: { model: 'nav' }></div>

I have also tried:

<div>
    <!-- ko compose: 'viewmodels/nav' -->
    <!-- /ko -->
</div>

along with other variations like view: 'nav', where appropriate, etc.

I have even tried creating a child router and returning the child router, using the same routes as the router, and binding nav.html to the child router, and still no navigation activity occurs.

Different configurations of the above will properly display the nav.html with its nav buttons, but in no configuration does the web page respond by retrieving the view linked to the button.

I'm new to durandaljs, and I know John Papa's video is based on an earlier version of durandaljs than I am currently using (his model was using sammy.js as the router), but I can't get this routing to work.

I did find where someone else was experiencing a similar problem (in Google Groups durandaljs) and he solved his problem using two lines of code in the activate() method of the router (his solution stated, "The issue was jQuery Mobile's navigation framework interfering with the Durandal router. Adding the following lines to the activate method in the my shell.js file solved the issue"):

$.mobile.linkBindingEnabled = false;
$.mobile.hashListeningEnabled = false; 

He appeared to be doing almost exactly what I'm trying to do but unfortunately, I get a 'Declarations of property 'mobile' were not found' message when I try to include those lines in my shell.js file (even though I am able to import jQuery as $ via the define signature of the shell.js file):

activate: function () {
    $.mobile.linkBindingEnabled = false;
    $.mobile.hashListeningEnabled = false;
    router.map(config.routesNLI).buildNavigationModel();
    return router.activate(my.viewToDisplay());
}

Any advice or suggestions would be greatly appreciated! Thanks in advance for your help.

RESOLUION

I appear to have some random issues with navigation, but using the recommendation provided by Krzysztof Cieslak, I changed the binding of my router in my third div to read:

<!-- ko router: { transition:'entrance' } -->
<!-- /ko -->

I then got rid of the references to jquery.mobile and now I am able to navigate to various pages. Unfortunately, the text being copied into the address bar is not always consistent; the reloading of view/viewmodels appears to always work when the url is copied as #/login, resulting in something like:

http://localhost:12345/index.cshtml#/login 

At other times, the address bar is missing the '#/', and navigation fails.

It appears I was guilty of using code written to work with sammy.js's router and not with the durandaljs router. I want to thank all of you who responded and hope to someday be in a position where I can return the favor.

1
Please add the requirejs.config. Sounds like jquery mobile isn't loaded yet. - RainerAtSpirit
Thanks for your reply! Hope I can comment multiple times as I have more than 500 chars to write. If not, I'll post remainder as an edit, I guess, as I'm new to this. You are absolutely correct. Up until a few mins ago, I didn't even know there WAS a jQuery mobile module, although it makes perfect sense that there would be. I now have renamed jquery.mobile-1.3.2.js to jqm.js in scripts folder and added it to load via @Scripts.Render("~/scripts/vendor") in index.cshtml. Relevant line in requirejs.config is 'jqm': '../scripts/jqm' & I pass in to shell.js (where router loads) using (define(['jqm' - user2054996
Now, I have IntelliSense which is recognizing linkBindingEnabled as a method now. The screen loads and displays properly, but when I click a link button, I get an error which states, "Uncaught TypeError: Cannot call method 'indexOf' of undefined" and references jqm.js:5136. - user2054996
Does it make sense that you would have to 'add' jquery.mobile in order to get around a conflict between the mobile router and the durandal router? As mentioned above, I had no reference to mobile, I just found a link on Google Groups durandal where a poster said his problem was solved by adding those two lines of code to his solution. - user2054996
here's that link, in case you're interested: groups.google.com/forum/?fromgroups=#!topic/durandaljs/… - user2054996

1 Answers

1
votes

Shell.html bindings

I am little bit confused as You only show us static binding to nav.html view and than You say that everything is rendering correctly before navigation. As far as I know Your shell.html should look like:

<div>
    <header>
        <!--ko  compose: {view: 'nav'} --><!--/ko-->
    </header>
        <div>
            <section id="content" class="main">
                <!--ko router: { transition:'entrance'}--><!--/ko-->
            </section>
        </div>
</div>

Where first binding is static nav.html binding and second one is dynamic view binding based on router.

Durandal & jQuery Mobile

As You have written there is a problem with interference between jQuery Mobile and Durandal routers. Simples way of solving it is editing global jQuery Mobile settings in file jqm-config.js ( it's in jQuery Mobile directory) so it looks like:

$(document).bind("mobileinit", function() {
        console.log("### Config loaded...");
        $.mobile.ajaxEnabled = false;
        $.mobile.linkBindingEnabled = false;
        $.mobile.hashListeningEnabled = false;
        $.mobile.pushStateEnabled = false;

        $.mobile.buttonMarkup.hoverDelay = 100;

        $.mobile.autoInitializePage = false;
});