如何控制Durandal中视图激活的顺序

时间:2013-11-11 17:34:59

标签: durandal

我正在使用Durandal 2.0构建应用程序 我的shell视图如下所示:

<div>
    <header id="nav" data-bind="compose: 'viewmodels/nav', activate: false">
    </header>
     <section id="content" class="main container-fluid" data-bind="router: { transition: 'entrance' }, activate: false" style="overflow: auto">
     </section>
    <footer>
        <!--ko compose: {view: 'footer'} --><!--/ko-->
    </footer>
</div>

在导航部分,我想要我的标签和用户的下拉列表(两者都是从Web服务检索的)。从下拉列表中选择用户将导航到将更新内容部分的新URL。 (该路线看起来像localhost /#user1 / tab2)。

  • 问题:我需要先知道导航部分中的所选用户,然后才能检索内容部分的数据,但在检索用户之前,内容部分正在激活。

这实际上只是初始页面加载的问题,因为用户列表只被检索一次。

  • 有没有办法让内容部分等到导航部分完成加载?
  • 有什么比我正在做的更好的方法吗?

导航激活功能如下所示:

function activate(context) {        
    return dataservice.getUsers().then(function () {
        //do stuff
    });
}); 

首先调用此activate函数,并调用dataservice.getUsers(),然后在“do stuff”部分发生之前调用内容模块的activate函数(并且在返回getUsers调用的数据之前)数据服务)。也许我的承诺有问题?

修改
我把一个实际的代码放在一起,展示了我在说什么:http://jerrade.github.io/dFiddle-2.0/#test/dashboard
代码在这里:https://github.com/jerrade/dFiddle-2.0

nav.js

 function activate(context) {
     console.log('Nav View Activated');
     if (vm.impersonateUsername == undefined)
         vm.impersonateUsername = getUsernameFromWindowLocation();

     return dataservice.getPageDetailForEmployee(vm.loggedInUsername, vm).then(function () {
         console.log("Page details retrieved");

         // I want to do something here before the dashboard activates.
     });
  }

dashboard.js

 function activate(username) {
        console.log('Dashboard View Activated');
        //vm.username = nav.selectedImpersonateEmployee().Username;        
        return dataservice.getDashboard(nav.impersonateUsername, dashboard);
    }

打开页面并观看控制台。你会看到(除其他外)

Nav View Activated  
Dashboard View Activated  
Page details retrieved 

我真正想要的是在仪表板视图激活之前检索页面详细信息。我实际上已经重新调整了一些东西,以至于这不再是一个问题,但它可能会再次出现问题。

似乎我想要做的事情应该是这么复杂。除非我在这里把一个方形钉子撞到一个圆孔上?

1 个答案:

答案 0 :(得分:0)

最简单的方法是在视图模型上添加一个名为isUserLoaded的可观察对象。然后,在内容部分周围应用if绑定:

<div>
    <header id="nav" data-bind="compose: 'viewmodels/nav', activate: false">
    </header>
    <!-- ko if: isUserLoaded -->
     <section id="content" class="main container-fluid" data-bind="router: { transition: 'entrance' }, activate: false" style="overflow: auto">
     </section>
    <!-- /ko -->
    <footer>
        <!--ko compose: {view: 'footer'} --><!--/ko-->
    </footer>
</div>

加载用户后,您可以将观察结果更新为true,并且您的内容绑定应该会触发。

修改

如果这不起作用,听起来你的路由器仍然必须解析内容视图模型(可能指向路由问题?很难说没有看到整个解决方案)。

无论如何,如果它不是路由问题,那么您可以使用一个解决方案,其中您的内容模型从其activate方法返回未解析的promise;然后在加载用户时解决该承诺。例如,沿着这些方向:

userModel.js:

define([], function () {
    // single instance to track the loaded user
    var userModel = {
        selectedUser: ko.observable()
    };

    return userModel;
});

navModel.js:

define(["dataService", "userModel"], function(dataService, userModel) {
    // view model for the nav bar
    var navModel = {        
        // model definition
    };

    // load the user
    navModel.activate = function() {
        return dataService.getUsers().then(function(response) {
            // Push the user to the userModel
            userModel.selectedUser(response.user);
        });
    };

    return navModel;
});

contentModel.js:

define(["userModel"], function (userModel) {
    var contentModel = {
        // model definition
    };

    contentModel.activate = function () {
        // Prevent activation until user is resolved
        var deferred = $.Deferred();

        var subscription = userModel.selectedUser.subscribe(function (user) {
            if (!user)
                return;

            subscription.dispose();
            deferred.resolve();
        });

        return deferred.promise();
    };

    return contentModel;
});

如果您不想对userModel.selectedUser属性使用observable,则可以改为使用另一个延迟,或者在用户加载等时触发事件等。无论你的船是什么漂浮!