【问题标题】:Using ko.mapping with Knockout Components in SPA在 SPA 中将 ko.mapping 与 Knockout 组件一起使用
【发布时间】:2016-06-10 12:45:46
【问题描述】:

我正在尝试使用 KnockoutJS SPA Yeoman 生成器来构建 SPA 应用程序并使用 ko.mapping 插件。我已经调整了 require.config.js 以包含 ko-mapping。

在独立应用程序中,我可以让映射插件正常工作,但是当我尝试在组件的构造函数中使用它时,绑定在模板 html 中永远不可用。关于我可能做错了什么让映射插件在 KO 组件中播放的任何想法?

var require = {
    baseUrl: ".",
    paths: {
        "bootstrap":            "bower_modules/components-bootstrap/js/bootstrap.min",
        "crossroads":           "bower_modules/crossroads/dist/crossroads.min",
        "hasher":               "bower_modules/hasher/dist/js/hasher.min",
        "jquery":               "bower_modules/jquery/dist/jquery",
        "knockout":             "bower_modules/knockout/dist/knockout",
        "komapping":            "bower_modules/knockout-mapping/knockout.mapping",
        "knockout-projections": "bower_modules/knockout-projections/dist/knockout-projections",
        "signals":              "bower_modules/js-signals/dist/signals.min",
        "text":                 "bower_modules/requirejs-text/text"
    },
    shim: {
        "bootstrap": { deps: ["jquery"] },
        "komapping": { deps: ["knockout"], exports: 'komapping'}
    }
};

define(['jquery', 'knockout', './router', 'bootstrap', 'knockout-projections'], function($, ko, router) {
      // Components can be packaged as AMD modules, such as the following:
      ko.components.register('nav-bar', { require: 'components/nav-bar/nav-bar' });
      ko.components.register('home-page', { require: 'components/home-page/home' });

      // ... or for template-only components, you can just point to a .html file directly:
      ko.components.register('about-page', {
        template: { require: 'text!components/about-page/about.html' }
      });

      ko.components.register('bems', { require: 'components/bems/bems' });
      ko.components.register('user-page', { require: 'components/user-page/user' });
      ko.components.register('team-page', { require: 'components/team-page/team' });
      ko.components.register('exec-page', { require: 'components/exec-page/exec' });

      // [Scaffolded component registrations will be inserted here. To retain this feature, don't remove this comment.]

      // Start the application
      ko.applyBindings({ route: router.currentRoute });
});

define(['knockout', 'text!./bems.html','komapping'], function(ko, templateMarkup, komapping) {
    function Bems(params) {
        ko.mapping = komapping;
        var self = this;
        self.response = ko.observable();

        if (typeof params[0] != 'undefined') {
          // Suppress search while loading
          document.getElementById("bems-input").style.visibility = "hidden";
          self.bemsId = String(params[0]);

          $.ajaxSetup({
            cache: false,
            "error":function() { 
              document.getElementById("bems-input").style.visibility = "visible";
              window.location = ("#/bems/");
            }  
          });

          $.getJSON('/app/skyline/api/bems/' + self.bemsId, function(ajax_response) {
              document.getElementById("bems-input").align = "right";
              document.getElementById("bems-input").style.visibility = "visible";
              document.getElementById("bems-container").style.visibility = "visible";
              ko.mapping.fromJS(ajax_response, {}, self.response);
          });
        }
        // Nothing to do without bemsId parameter
    }

    return { viewModel: Bems, template: templateMarkup };
});

我还测试了以下更改:

self.response = ko.observable();
self.message = ko.observable("It works");

$.getJSON('/app/skyline/api/bems/' + self.bemsId, function(ajax_response) {
    self.response = ko.mapping.fromJS(ajax_response);

在上面self.message 正确绑定并且可以在模板中访问。但是self.response 中的映射属性未绑定。

我的工作设置和损坏案例之间的主要区别在于工作示例中我将 ko.mapping 结果设置为整个视图模型变量,其中函数 Bems 是视图模型,这是 vm 下的变量.

我今天又看了一遍,并接近了这个问题。看起来主要问题是触发 AJAX 回调和通过 Yoeman 组件应用程序框架发生的绑定之间的操作顺序。如果我执行以下操作并在主 ViewModel 中延迟 2 秒,它会设法加载视图中第一个绑定属性的绑定内容,但随后会因 TypeError 而死,即使数据确实为属性加载。这会暂停脚本并且不会加载其他属性。

require.js:900 TypeError: Unable to process binding "text: function (){return response().engagement_list()[0].CASE_TITLE }"(…)

function BemsViewModel(params) {

 self.response = ko.observable();

      $.getJSON('/app/skyline/api/bems/' + self.bemsId(),          function(ajax_response) {
          $("#bems-input").attr("align","right");
          $("#bems-input").attr("style", "visibility: visible")
          $("#bems-container").attr("style", "visibility: visible")
          var foobar = {};
          ko.mapping.fromJS(ajax_response, {}, foobar);
          self.response(foobar);

是否有任何最佳实践/模式来确保仅在使用此 KO 组件 SSA 模板加载视图模型的所有位后才发生绑定?任何帮助/想法将不胜感激。我真的不想手动定义整个视图模型...

【问题讨论】:

    标签: javascript knockout.js


    【解决方案1】:

    好的,我现在有这个工作。关键是执行上述操作,将映射属性正确添加到现有视图模型中,但还必须使用 data-bind with 属性来映射此动态内容。这样, ko.binding 函数只会深入到顶层,并且不会抱怨它下面缺少属性。由于这些在 viewmodel 已经绑定后加载 asyc,因此这些数据将在事后填充。

    http://knockoutjs.com/documentation/with-binding.html

    <div id="bems-dyn" data-bind="with: response">
     <p>BEMS Title: <span data-bind="text: engagement_list()[0].CASE"></span></p>
     <p>Container Type: <span data-bind="text: global_params.container_type"></span></p>
     <p>BEMS Id: <span data-bind="text: global_params.bems_id"></span></p> 
    </div>
    
    self.response = ko.observable();
    
      $.getJSON('/app/test/api/bems/' + self.bemsId(), function(ajax_response) {
          $("#bems-input").attr("align","right");
          $("#bems-input").attr("style", "visibility: visible")
          $("#bems-container").attr("style", "visibility: visible")
          //self.response = ko.mapping.fromJS(ajax_response);
          var foobar = {};
          ko.mapping.fromJS(ajax_response, {}, foobar);
          self.response(foobar);
    

    【讨论】:

      猜你喜欢
      • 2017-04-30
      • 2017-02-20
      • 2013-03-24
      • 2014-04-15
      • 1970-01-01
      • 2014-03-06
      • 1970-01-01
      • 2015-11-23
      • 2016-02-15
      相关资源
      最近更新 更多