1

I am trying to configure the router to allow one model for multiple views.

It is a 'profile' module so I have a top level router like so:

.map([{ route: ['profile*details', ''], moduleId: 'myprofile', title: 'Your Profile', hash:'#profile', nav: false } ])

And in the myprofile.js module I have the child router:

define(['services/unitofwork', 'services/logger', 'durandal/system', 'durandal/activator', 'viewmodels/profile', 'plugins/router', 'durandal/app', 'services/errorhandler'],
function (unitofwork, logger, system, activator, Profile, router, app, errorhandler) {
    var MyProfile = function () {

        this.router = router.createChildRouter()
        .makeRelative({
            moduleId: 'my',
            fromParent: true
        }).map([
            { route: ['details'], moduleId: 'details', title: 'Details', type: 'intro', nav: true },
            { route: 'search', moduleId: 'jobsearch', title: 'Job Postings', type: 'intro', nav: true },
            { route: 'resume', moduleId: 'resume', title: 'Resume', type: 'intro', nav: true },
            { route: 'account', moduleId: 'account', title: 'Subscription', type: 'intro', nav: true }
        ]).buildNavigationModel();
 }
return MyProfile;
});

I was of the understanding that if I declared the main module with a splat route (profile*details), and that module returned a childrouter on the router property that defined the child-inner routes, that then I could maintain use of the child module to compose with each inner view.

Basically I want to use the viewmodels/myprofile.js module with the

views/my/details.html

views/my/resume.html

etcetera.

Using the unitofwork with Breeze, this pattern would enable me to enforce save checking on deactivate of each subview but without reloading the entire profile again.

It seems that the canReuseForRoute property could be of use, but I thought that it was not necessary given http://durandaljs.com/documentation/Using-The-Router.html - Module Reuse --

Consider the scenario where a history change causes a navigation that results in the same module as is already active and being viewed. Normally, even though the module is the same type, it will be discarded and a new instance created. There are two exceptions to this:

If the module has a child router associated with it. The instance will be kept. If the module has a special callback implemented, called canReuseForRoute, this function will be called allowing the developer to determine if the module should be discarded or not.

Am I missing something? Is it possible to achieve this?

Thanks.

JoeWarwick
  • 105
  • 2
  • 8
  • Not sure if I understand your question. What are you trying to achieve? – Adel Sal Mar 13 '14 at 15:35
  • I wanted the whole 'profile' viewmodel to exist in the same viewmodel that the childRouter was declared in, and for that model to stay in use while navigating around the parts.. – JoeWarwick Mar 16 '14 at 22:38
  • I ended up refactoring to split off each part into a separate viewmodel. – JoeWarwick Mar 16 '14 at 22:39

1 Answers1

0

I was of the understanding that if I declared the main module with a splat route (profile*details), and that module returned a childrouter on the router property that defined the child-inner routes, that then I could maintain use of the child module to compose with each inner view.

Your understanding is correct. However, the logic is that you'll have a another shell in your application and it can have its own menu.

I'm not sure if you've implement it but I'll post my answer anyway.

In your main shell.js at the top level router :

.map([{ route: 'profile*details', moduleId: 'myprofile', title: 'Your Profile', hash:'#profile', nav: false } ])

this will create a url for every viewmodel as :

#profile/details

#profile/jobsearch

#profile/resume .. etc..

Whereas, myprofile.js is your new shell. (i.e. it will act the same way as shell.js does).

myprofile.js:

define(['services/unitofwork', 'services/logger', 'durandal/system', 'durandal/activator', 'viewmodels/profile', 'plugins/router', 'durandal/app', 'services/errorhandler'],
function (unitofwork, logger, system, activator, Profile, router, app, errorhandler) {
    var MyProfile = function () {

        this.router = router.createChildRouter()
        .makeRelative({
            moduleId: 'my',
            fromParent: true
        }).map([
            { route: '', moduleId: 'details', title: 'Details',  nav: true },// This is your home page now at the child router level
            { route: 'search', moduleId: 'jobsearch', title: 'Job Postings', nav: true },
            { route: 'resume', moduleId: 'resume', title: 'Resume', nav: true },
            { route: 'account', moduleId: 'account', title: 'Subscription', nav: true }
        ]).buildNavigationModel();
 }
return MyProfile;
});

Notice the first route is empty because that is your new home page. I have omitted type:'intro' as that is unneeded in your case.(It's just a way to classify your routes in the UI)

myprofile will act as a new shell, so myprofile.html might look like:

   <div class="col-md-2">
   <ul class="nav" data-bind="foreach: router.navigationModel">
                <li data-bind="css: { active: isActive }">
                    <a data-bind="attr: { href: hash }, html: title"></a>
                </li>
            </ul>
    </div>
   <div class="col-md-10">
          <!--ko router: { transition:'entrance', cacheViews:true }--><!--/ko-->
      </div>

You can compose a new nav.html or just do it the same way I did. you can also make the child menu to be horizontal. I personally prefer it vertical ("col-md-2").

That definitely, will enable you to maintain the use of the child module to compose with each inner view and Unitofwork will only get loaded at the child level.

canReuseForRoute can be used in some cases like parameterized routes when you want to navigate within the same Viewmodel and changed parameter.(e.g. profile/1 to profile/2) indicating that this module can be reused for route or not.

Adel Sal
  • 718
  • 5
  • 16