【问题标题】:Durandal how to attach view and don't show it untill it's ready?Durandal 如何附加视图并且在它准备好之前不显示它?
【发布时间】:2014-09-01 16:20:40
【问题描述】:

这是我试图实现的不寻常场景: 我得到了gmap 异步加载谷歌地图的模块。我正在使用以下代码正确附加 Google 地图:

 composition.addBindingHandler('googleMap', {
        init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
            gmap = ko.utils.unwrapObservable(valueAccessor());

            var latLng = new gmaps.LatLng(37.774107,-122.420853);
            var mapOptions = {
                center:latLng,
                zoom: 17,
                disableDefaultUI: true,
                mapTypeId: gmaps.MapTypeId.ROADMAP
            };

            gmap.googleMap = new gmaps.Map(element, mapOptions);
            navigator.geolocation.getCurrentPosition(onSuccess, onError);
        }
    });

我的 gmap 模块是我想在用户登录后首先显示的模块。所以我想在显示这个模块之前执行一些操作。在大多数情况下,我可以在 canActivate 方法中使用 Promise,但是!在这种情况下,我的模块没有附加。但是我需要附加这个模块,执行一些操作(获取数据库记录,确定用户地理位置,根据这些数据在谷歌地图上添加标记)并且只有当它完成后才向用户显示模块。 我怎样才能得到这个作品?我尝试了 Promises,但它对我不起作用,因为我听了 attached 方法,该方法在显示模块之前不会触发。 所以问题是:如何激活附加视图模型及其适当的视图(激活和附加的回调应该触发)但不要显示它直到条件

更新: 好的,在我看来,我的问题并不是很清楚。这是我的场景:
1. 我的登录模块激活。用户应键入他的凭据。
2.一旦授权返回成功,Gmap模块应该被激活并附加,但不显示。用户仍应看到登录模块和消息,例如“正在加载数据...”
3. Gmap 模块应该完全加载(所有的回调都应该触发)。我需要与 DOM 交互的可能性,这意味着应该附加该模块。但没有显示。
4. 满足某些条件后,SignIn 模块将不可见并显示 Gmap。

激活回调中的承诺不适合这种情况,因为在承诺解决之前不会附加视图。基本上授权成功后我需要这样的东西:

router.navigate('#gmap', { show: false });
...或...
router.attachModule('#gmap', ...{});

为什么我需要与 DOM 交互,为什么激活回调中的 Promise 不适合我?因为我需要启动 Gmap 对象,该对象只能使用页面上现有的 gmap 画布启动:

 composition.addBindingHandler('googleMap', {
        init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
            gmap = ko.utils.unwrapObservable(valueAccessor());
            var mapOptions = {
             ...

            };

            gmap.googleMap = new gmaps.Map(element, mapOptions);

        }
    });

还有 HTML:

<div id="gmap-section">
    <div id="gmap-canvas" data-bind="googleMap:map"></div>
</div>

绑定仅在视图附加后才起作用。

【问题讨论】:

  • 完成所有任务后,如何通过敲除可见绑定隐藏它并设置为true?
  • 当路由器从我的登录模块导航到我的 gmap 模块时,它会隐藏我的登录模块。所以,我看不到 gmap 模块,因为它还没有准备好(例如,被 display:none 隐藏)而且我看不到我的登录模块,因为它被 Durandal 的路由器隐藏了。

标签: javascript single-page-application durandal durandal-2.0


【解决方案1】:

我还没有完全理解你的问题,但我会试着给你一些思考的食物。 ViewModel,在最佳实践中,应该只负责纯视觉相关的东西。所以任何繁重的计算、数据库连接或其他任何东西都应该被拉到一个单独的服务中。在 Durandal 的情况下,这只是一个简单的 RequireJS 模块。这应该是一个单例,并且可以被多个虚拟机所需要。

这样做并不是绝对需要立即拉入新的虚拟机,而是在登录时开始计算,完成后继续加载新的 GMapVM。

至于如何做到这一点,您可以在 SignIn 中启动服务调用并在 Promise 完成后导航到 GMapVM,或者如果您不喜欢 Promises,则使用 Durandal 内置的 Pub/Sub 流程。


从 Durandals 内部系统开始,GMapVM 的 canActivate 可能也是一个合适的解决方案,或者可以从 SignInVM 取消激活

【讨论】:

  • canActivate 方法中的 Promise 不是解决方案,因为附加不会触发。 canDeactivate 也不是解决方案,因为它在 canActivate 之前进行,所以即使 canActivate 也不会触发。我想这样做,因为我想在显示 gmap 模块之前在地图上添加标记。所以用户只会看到加载的地图,上面有所有的标记。如您所见,在这种情况下,视图逻辑与视图模型紧密相关。或者我可以确定,如果我在“激活”上加载所有数据,但在“附加”上根据这些数据添加标记,用户将看不到添加标记的过程?
  • 抱歉重复评论,但这里是另一个例子:link 如你所见,我需要 gmap 对象才能使用路线服务。例如,我想根据某些条件计算道路,并在我的 gmap 模块加载时显示它。所以用户不应该看到构建路线的过程。在显示 gmap 之前,我可能会出于某些目的使用估计的时间(例如,到 A 点约 5 分钟)。但我不能,因为我只能在我的 gmap 模块被附加并且组合处理程序完成之后才能访问 gmap。
  • 你的布局文件“index.html”或任何被调用的文件应该有一个id为“applicationHost”的div,那么如何在其中添加一个可见的绑定并在计算完成时将其设置为false,然后再设置为true?
  • 使 applicationHost 不可见使我的所有视图也不可见,因为它们附加在 applicationHost 内。我想显示授权窗口,只有在成功登录的情况下才进行所有计算。
【解决方案2】:

如果您的 activate 方法返回一个承诺,Durandal 的路由器将等到该承诺解决后再路由到文档中提到的新路由 - http://durandaljs.com/documentation/Using-The-Router.html

如果您想创建自己的 Promise 并使用 setTimeout 在您的应用中进行演示。

function activate () {
    var promise = Q.deferred();
    setTimeout(function () { promise.resolve(true); }, 5000);
    return promise;
}

这将向 Durandal 的路由器返回一个 Promise,然后 5 秒后它将解决该 Promise。在 promise 解决之前,您应该会看到旧路线。

编辑

好的,在这里说明很明显,但是从 cmets 听起来,您在激活完成和附加回调完成之间遇到了问题。放弃我之前所说的话,这是一种快速而简单的方法,可以完成听起来像是你想要完成的事情,但很难确定,因为我不太明白你在问什么......

var showGmapStuff = ko.observable(false);

function activate () {
    var promise = Q.deferred();
    initializeStuff(promise);
    return promise;
}

function initializeStuff(promise) {
    connecttoserver();
    dootherstuff().then(finished);

    function finished() {
        promise.resolve(true);
    }
}

function attached () {
    showGmapStuff(true);
}

在你看来——

<div data-bind="if: showGmapStuff">
    <div data-bind="gmap: mapdata"></div>
</div>

在这种情况下,gmap 绑定将不存在,直到激活返回一个承诺并且附加的回调将 showGmapStuff 设置为 true。这样一来,它就不会被视为 false ,而是在您想要它之前根本不会被评估。

【讨论】:

  • 是的。但如文档中所述,模块激活在“激活”阶段停止。我需要的“附加”阶段稍后会进行,并且使用承诺它不会触发。在最底部您可以找到回调顺序 - link
  • 你是什么意思,你需要它,附加后总是触发。
  • 我也说过。因此,如果我在 activate 中发送 Promise,我的附加回调将不会触发,直到 promise 无法解决。我需要附加我的模块,以便它可以使用 DOM 进行操作。
  • 为了记录,我不需要到 Durandal 文档的链接,但我很欣赏这个姿态。另外,我们无法理解您正在寻找的解决方案的原因是因为我们不理解问题所在。我已经用一些相当琐碎的做法编辑了我的问题,这些做法应该适用于我认为您所描述的情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多