我正在尝试使用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模板加载视图模型的所有位之后才进行绑定?任何帮助/想法将不胜感激。我真的不想手动定义整个视图模型......
答案 0 :(得分:1)
好的,我现在有这个工作。关键是要执行上述操作,将映射的属性正确添加到现有视图模型中,但还必须使用带有属性的data-bind来映射此动态内容。这样ko.binding函数只能挖到顶层,并且不会抱怨它下面缺少属性。由于这些在视图模型已经绑定后加载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);