knockout.js - BreezeJS与DurandalJS的集成与如何加载KnockoutJS有关的问题

标签 knockout.js breeze durandal q

Durandal.JS和Breeze.JS在一起玩会有一些麻烦。 Durandal基于一些库,注意的两个是Require和Knockout。在使用Require引入的模块化模式之前,我的原始项目在Breeze模型上使用了Knockout样式绑定。

在旅途中,我发现Breeze可以与Breeze模型的多个库一起使用,例如Backbone,Knockout,Angular和其他框架。当将Breeze加载为Require模块时,Breeze会检查别名是否存在用于Knockout的模块。该模块名称与Durandal如何别名为Knockout冲突,因为Durandal改用模块名称“ knockout”。

当Breeze加载时,将进行检查以确定如何呈现Breeze模型的数据属性。在我的原始项目中,Breeze将在全局范围内检测到Knockout并将所有属性分配为“ ko.observable()”样式属性。

我如何才能使这些模块正常运行?我尝试了几种Require.JS技巧,例如添加以下Shim:(from this post)

breeze: { deps: ['ko', 'jQuery', 'Q'] }


并添加以下虚拟模块定义:

define('ko', ['knockout'], function (ko) { return ko; });
define('Q', ['q'], function (Q) { return Q; });
define('jQuery', ['jquery'], function ($) { return $; });


在我的main.js中。该组合使Breeze可以运行。我能够针对后端API成功执行查询。

但是,结果不能正确地变为可观察到的淘汰赛。相反,Breeze似乎正在使用本机ES5可观察的属性。虽然这实际上有点酷,但它完全破坏了我现有的模块。

需要注意的是,正如Druandal文档所建议的那样,我将使用Q提供的片段覆盖内部Promise库。

   system.defer = function (action) {
        var deferred = Q.defer();
        action.call(deferred, deferred);
        var promise = deferred.promise;
        deferred.promise = function () {
            return promise;
        };
        return deferred;
    };


尽管上面的垫片和虚拟模块纠正了此问题,但Q库和jQuery库也出现了这些相同的问题。我不知道下一步该怎么做。

编辑:为响应“显示您的上下文设置”注释:

define([
'breeze',
'q',
'durandal/system',
'lodash'
],
function (breeze, Q, system, _) {
    return new function () {
        var self = this;

        self.create = create;
        self.init = init;

        var EntityQuery = breeze.EntityQuery;
        var BREEZE_URL = '/breeze/AtlasApi/';
        var masterManager = new breeze.EntityManager(BREEZE_URL);
        self.masterManager = masterManager;

        function init() {

            return masterManager.fetchMetadata()
                    .fail(function (error) {
                        system.error(error);
                    });
        };
        function create() {
            var manager = masterManager.createEmptyCopy();

            return manager;
        };
    };
});


上面的模块我在AppStart加载一次,并调用Init方法以确保我具有元数据。然后,我在其他地方调用.create()来创建一个空的隔离副本。这在非Require.js环境中效果很好。我使用promises来确保init步骤已经完成。我可以手动运行查询,并且它们可以正常工作,而无需通过Breeze实现实体的方式(同样,作为ES5属性,而不是敲除属性)

最佳答案

看起来您正在尝试通过requireJS加载每个库。我记得,开箱即用的Durandal方法是直接加载第三方脚本(在require之外),并且仅对应用程序脚本使用require。

这简化了事情,但这并不是唯一的方法,很多人想要使用require来加载所有脚本。

我们最近(v.1.4.7)更新了“ Todo-Require”样本,以演示该方法。我意识到这不是Durandal应用,但希望您能找到所需的方向。

我将在此复制我认为对您有帮助的要点。

index.html

...
<body>
    <div id="applicationHost"></div>

    <!-- Require + main. All scripts retrieved async by requireJS -->
    <script data-main="Scripts/app/main" src="Scripts/require.js"></script>
</body>
...


main.js

(function () {
    requirejs.config({
        paths: {
            'breeze': '../breeze.debug',
            'jquery': '../jquery-1.8.3.min',
            'ko':     '../knockout-2.2.0',
            'Q':      '../q'
        }
    });

    //  Launch the app
    //  Start by requiring the 3rd party libraries that Breeze should find
    define(['require', 'ko', 'jquery', 'logger', 'Q'], function (require, ko, $, logger) {
        logger.info('Breeze Todo is booting');

        // require the 'viewModel' shell 
        // require '../text' which is an html-loader require plugin; 
        //     see http://requirejs.org/docs/api.html#text
        require(['viewModel', '../text!view.html'],

        function (viewModel, viewHtml) {
            var $view = $(viewHtml);
            ko.applyBindings(viewModel, $view.get(0));
            $("#applicationHost").append($view);
        });
    });
})();


请注意,我们如何使用路径来定位库并获得Breeze期望的建立的模块名称。

还要注意,在Breeze本身加载之前,我们强制requireJS加载这些依赖的第三方库。那真的很重要。在Breeze开始寻找它们时,它们必须位于requireJS IoC容器中。如果他们不在,Breeze会认为他们永远不会在那里。

这就是为什么您会看到Breeze将实体属性视为ES5属性的原因。呼叫“上下文设置”中的define同时加载“ ko”和“微风”。这意味着当Breeze在其自身的初始化阶段寻找'ko'时,无法保证将其加载。

如果在Breeze查找“ ko”时未将其加载,则Breeze会假定您未使用Knockout并返回其本机模型库(“ backingStore”)...将实体构建为ES5属性。这恰好是Angular应用程序的正确选择。这不是KO应用程序的正确选择。

最后,如果Durandal期望模块使用不同的名称(我会为您效忠),请使用requireJS“ map”配置来定义同义词,如下例所示:

requirejs.config({
    paths: {
        'breeze': '../breeze.debug',
        'jquery': '../jquery-1.8.3.min',
        'ko':     '../knockout-2.2.0',
        'Q':      '../q'
    },
    map: {
        '*': { 'knockout': 'ko' }
    }
});


现在,当Durandal请求“淘汰”时,requireJS会将其映射到(已加载的)“ ko”模块。

这种“地图”技术代替了同样有效的“虚拟模块”方法:

define('knockout', [ko], function (ko) { return ko; });


在查看示例代码时,您可能会想知道此应用何时加载Breeze。答案:viewModel解析后。 viewModel有其自己的依赖项,其中包括dataservice本身依赖于Breeze。依赖注入不是很棒吗? :-)

另类

您也许还可以通过其他方式解决问题。

根据您的问题,可以启动并运行Breeze和Durandal,但是Breeze模型库似乎已为Breeze的本机“ backingStore”配置,该实体将实体属性写为ES5 getter / setter属性。

您可以在以后的启动过程中(可能是在您第一次与Breeze交互并创建dataservicedatacontextEntityManager模块中)更改该选择。

在进行第一次微风互动之前,请致电

breeze.config.initializeAdapterInstance("modelLibrary", "ko", true);


这建立了淘汰模式,因为Breeze在创建/实现实体时应使用模型库。此后,将创建具有KO可观察属性的实体。

至关重要的是,在进行此配置更改之前,将剔除加载到requireJS IoC容器中并以“ ko”访问,否则Breeze会引发异常。

不要期望Breeze等到requireJS异步加载了'ko'。适配器初始化是一个同步过程。在微风寻找它之前,必须先装载“ ko”。

杜兰达2.0

我得知Durandal v2.0改变了我在Durandal v.1.x中熟悉的安装模式。我相信我的回答仍然贴切。

我对Durandal v.2不太熟悉。我对此感到很兴奋,部分原因是它提供了使用ES5属性获取器/设置器而不是可观察性函数的可能性。我喜欢那一吨!

这项特定功能(不必使用)的代价是必须在与ES5兼容的浏览器中运行……这意味着您无法在仍流行的IE8中运行。没有ES5属性的polyfill。

大多数(但不是全部)单页应用程序可以在此限制内运行。

不幸的是,根据Durandal的架构师说,在当前的2.0版本中,ES5属性不适用于Breeze。这两个库在争夺那些getter和setter方法。因此,您可以将Durandal v2.0与Breeze一起使用,但现在必须保留可观察的函数属性。

我们希望这个故事在2.1版之前有所改善

总共

希望这些想法和变化能使您走上成功的道路。

关于knockout.js - BreezeJS与DurandalJS的集成与如何加载KnockoutJS有关的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21006421/

相关文章:

javascript - Knockout JS 文本输入绑定(bind)

javascript - 将行为附加到由knockoutjs创建的元素

Javascript 构造函数模式和垃圾收集器

javascript - 由 foreach Knockout.js 构建的表内的动态复选框 - 将依赖项设置为启用

javascript - KnockoutJS - 映射和扩展器

asp.net-mvc-4 - BreezeController 中如何调用 SaveChanges()?

javascript - 如何使用Durandal的createChildRouter

c# - 使用 Breeze 手动应用 OData 查询选项并仍然返回 InlineCount

html - Angular/Breeze - 无法在 HTML 文本输入中输入小数点