2

This works well for getting a sub menu to work within a main view.

I was able to get the activate() function to work for the sub menu viewmodels by adding activate: true to the compose binding. The other life cycle events are not firing though. How do I get canActivate(), canDeactivate() and deactivate() to work within my sub viewmodels?

Refer to the link at the top of my post for the source code. The answer to this linked question contains an example that I've used to integrate this functionality into a Hot Towel project.

Community
  • 1
  • 1

2 Answers2

2

Looks like the way @evan-larsen constructed the inAbout activator() prevents the execution of the canDeactivate and Deactivate events. Not sure why yet.

By converting it to use system.acquireinstead I was able to make those events fire again.

return system.acquire(convertSplatToModuleId(activationData.splat)).then(function( Sample ) {
       App.inAbout(new Sample());
   });

Here's the modified about/index.js.

define(
  ['durandal/system', 'durandal/viewModel', 'durandal/plugins/router'],
  function( system, viewModel, router ) {
      var defaultPage = 'aboutUs';

      function convertNameToModuleId ( name ) {
          return 'deepLinkingExample/areas/about/' + name + '/' + name;
      }

      function convertSplatToModuleId ( splat ) {
          if ( splat && splat.length > 0 ) {
              return convertNameToModuleId(splat[0]);
          }
          return convertNameToModuleId(defaultPage);
      }

      var App = {
          inAbout: viewModel.activator(),

          activate: function( activationData ) {

                  return system.acquire(convertSplatToModuleId(activationData.splat)).then(function( Sample ) {
                      App.inAbout(new Sample());
                  });
          },

          showPage: function( name ) {
              return function() {
                  router.navigateTo('#/about/' + name);
              };
          },

          isPageActive: function( name ) {
              var moduleName = convertNameToModuleId(name);
              return ko.computed(function() {
                    return this.inAbout().__moduleId__ === moduleName;
              }, this);
          }
      };

      return App;
  }
);

The code above assume that your returned detail VMs are ctors. An aboutMe.js like the below should do it.

define(['durandal/app', 'durandal/system'], function (app, system) {

    var ctor = function() {
           this.name = "About me";
           this.description = "For demonstration only";
       };

       ctor.prototype.canActivate = function () {
           return app.showMessage('Do you want to view ' + this.name + '?', 'Master Detail', ['Yes', 'No']);
       };

       ctor.prototype.activate = function() {
           system.log('Model Activating', this);
       };

       ctor.prototype.canDeactivate = function () {
           return app.showMessage('Do you want to leave ' + this.name + '?', 'Master Detail', ['Yes', 'No']);
       };

       ctor.prototype.deactivate = function () {
           system.log('Model Deactivating', this);
       };

       return ctor;
});
RainerAtSpirit
  • 3,723
  • 1
  • 17
  • 18
  • When responding 'No' in your canDeactivate() does the url change back to the correct page? As I try to navigate away from a page the url changes and then if I respond 'No' it doesnt change back. – Fred Gassmann May 14 '13 at 19:19
0

According to the docs activate: true won't add the complete life cycle events

Note: Cases 3 and 4 are a bit different as they only enforce canActivate and activate callbacks; not the deactivation lifecycle. To enable that, you must use a full activator yourself (cases 1 or 2).

So you have to create a full activator that controls the sub menu. Take a look at https://github.com/BlueSpire/Durandal/blob/master/App/samples/knockout/index.js#L6 for an example.

In short:

define(['durandal/viewModel'], function (viewModel) {

    return {
        activeSample:viewModel.activator(),
        ...  
Joseph Gabriel
  • 8,339
  • 3
  • 39
  • 53
RainerAtSpirit
  • 3,723
  • 1
  • 17
  • 18
  • I've read that in the docs and this certainly seems to be the case as activate() and canDeactivate() work. What's odd is I am using viewModel.activator() and the other callbacks still don't fire. If you refer to the sample project the activator is on line 19 of the app/deepLinkingExample/areas/about/index.js file. – Fred Gassmann May 09 '13 at 19:57
  • Sorry wasn't talking about @evanlarsen deepLinkingExample, I used the knockout samples from Durandal's source as an example. If you're on github feel free to fork/clone https://github.com/dFiddle/dFiddle-1.2 and reproduce the issue. – RainerAtSpirit May 09 '13 at 20:08