9

我有一个使用 Breeze 的 Angular 应用程序,它为我的不同控制器提供了一个共享的 EntityManager。无需执行查询即可访问我的一些控制器以预填充 EntityManager 的 MetadataStore。我在这里找到了一个起始方向,即在应用程序开始时获取元数据。我的项目基于 Angular-Breezejs 模板,当我尝试执行以下操作时出现错误,因为在某些东西使用数据上下文之前,promise 没有完全解决。

app.factory('datacontext',
    ['breeze', 'Q', 'model', 'logger', '$timeout',
        function (breeze, Q, model, logger, $timeout) {
            logger.log("creating datacontext");

            configureBreeze();
            var manager = new breeze.EntityManager("/api/app");            
            manager.enableSaveQueuing(true);

            var datacontext = {
                metadataStore: manager.metadataStore,
                saveEntity: saveEntity,
                getUsers: getUsers,
                getUser: getUser,
                createUser: createUser,
                deleteUser: deleteUser
            };

            return manager.fetchMetadata()
                    .then(function () {
                        model.initialize(datacontext);
                        return datacontext;
                    })
                    .fail(function (error) {
                        console.log(error);
                        return error;
                    });
            //Function definitions

在元数据获取完成之前阻塞的正确方法是什么?因为似乎没有必要在每个非查询功能(包括实体创建)之前检查元数据是否存在,就像上面链接问题的原始海报最终做的那样。

4

1 回答 1

11

我看到了你的问题。

当 Angular 调用你的工厂函数来创建 DataContext 服务时,它期望立即(同步)返回一个DataContext可以使用的对象。但是你正在返回一个在未来某个时间返回的承诺DataContext......而Angular并不是为此而构建的。

不过我喜欢这个主意。你可能想把它推荐给 Angular 团队 :-)。

所以你在这里尝试的只是行不通。您必须DataContext立即返回。在元数据到达之前,您必须阻止整个 UI 或阻止依赖元数据的特定功能(例如,createUser)。这有点像在使用 jQuery 操作之前等待 DOM 稳定下来。

这种情况不是 Angular 特定的。您在 Knockout 应用程序中面临同样的困境。分辨率类似。

首先在 DataContext 上公开某种“whenReady”钩子。承诺可能是个好主意。像这样的东西:

功能(微风,Q,模型,记录器,$超时){
    logger.log("创建数据上下文");
    ...
    var readyDeferred = Q.defer(), whenReady = readyDeferred.promise;

    变量数据上下文 = {
            何时就绪:何时就绪,
            ...
        };

    初始化数据上下文();

    返回数据上下文;// 现在 Angular 很高兴,因为它有一个数据上下文

    函数初始化数据上下文(){
        manager.fetchMetadata()
               .then(函数(){
                   readyDeferred.resolve();
                   // 做成功的事;
               })
               .失败(功能(错误){
                   readyDeferred.reject(错误);
                   // 做错误的事情;
               });
    }

    //函数定义
}

在你的应用程序启动的其他地方,你与datacontext.whenReady承诺联系在一起。

    // 在你的主控制器里面的某个地方
    $scope.isReady = false;
    datacontext.whenReady.then(function() {
           $scope.isReady = true;
           $scope.$apply();
       })
    .fail(function() { alert("哦哦!"); });
    ...

现在将范围绑定isReady到 HTML,以便您获得所需的行为。您可以使用它来阻止整个 UI 或只是封闭功能(例如,“创建用户”),直到数据上下文准备好。

请不要从字面上使用这个伪代码。用它来获得灵感。

于 2013-04-17T20:47:03.530 回答