Knockout 组件 - 从子 ViewModel 动态应用绑定
Knockout component - Apply Binding Dynamically from Child ViewModel
我有一个 knockout component
,它呈现员工的姓名。在这个组件中,我可以通过 callback
函数来改变显示的员工姓名的格式。
但是我遇到了无法更改组件代码的情况。但是我必须添加编辑按钮来显示模态弹出窗口来更新用户信息,如下图所示:
一些我如何使用组件提供的 callback
功能设法显示此编辑按钮。但是我遇到了绑定此按钮的 click event
的问题。
问题是:即使我定义了回调函数 ShowModal
,它也没有被调用。
这是我的代码:
组件注册:
ko.components.register('emp-box', {
viewModel: function(params) {
var self = this;
self.Name = ko.observable();
self.Callback = params.formatCallback;
if(self.Callback !== undefined)
{
self.Name(self.Callback(params.EmpName));
}
else
{
self.Name(params.EmpName.firstName + ', ' + params.EmpName.lastName);
}
},
template: '<div class="name-container"><span data-bind="html: Name"></span></div>'
});
ViewModel
var vm = function() {
var self = this;
self.Emps = [{'Details': {firstName: 'First Name-A', lastName: 'Last Name-A'}},
{'Details': {firstName: 'First Name-B', lastName: 'Last Name-B'}}];
// CALLBACK
self.changeFormat = function(item)
{
return item.firstName + ' - ' + item.lastName + ' <span class="action" data-bind="click: ShowModal">Edit</span>';
}
self.ShowModal = function(item)
{
alert(1);
}
}
ko.applyBindings(new vm());
HTML:
<div data-bind='foreach: Emps'>
<div data-bind='component: {
name: "emp-box",
params: {EmpName: Details, formatCallback: $root.changeFormat}
}'></div>
</div>
工作 Fiddle: Fiddle
如评论中所述,您正试图通过 html
绑定添加更多 "knockout code" 来使视图动态化。这行不通。
在 html
绑定甚至 运行 之前,knockout 一定已经弄清楚了绑定,否则它怎么知道它需要 运行 html
捆绑?一旦绑定阶段完成,它就完成了。因此,您不能以这种方式注入更多的敲除绑定。
Knockout 视图很灵活,只需添加您希望它们具有的所有部分并动态显示它们。在这种情况下,您希望有一个按需显示的 "Edit" 按钮。使用 if
绑定很容易:
<div class="name-container">
<span data-bind="text: displayName"></span>
<span class="action" data-bind="if: canEdit, click: onEdit">Edit</span>
</div>
现在控制它的视图模型需要一个 canEdit
值和一个 onEdit
值,分别是布尔值和函数。这些可以在组件绑定时通过params
来控制。
当您将 displayName 计算为计算并将名称格式化函数存储在可观察对象中时,您甚至可以动态切换名称格式。 运行 下面的代码示例可以看到它的实际效果。
// emp-box.component.js ----------------------------------------------------
function standardNameFormat(emp) {
return ko.unwrap(emp.lastName) + ', ' + ko.unwrap(emp.firstName);
}
ko.components.register('emp-box', {
viewModel: function (params) {
this.emp = params.emp;
this.displayName = ko.computed(function () {
var formatter = ko.unwrap(params.formatter) || standardNameFormat;
return formatter(params.emp);
});
this.canEdit = params.canEdit;
this.onEdit = params.onEdit;
},
template: '<div class="name-container">\
<span data-bind="text: displayName"></span>\
<span class="action" data-bind="if: canEdit, click: onEdit">Edit</span>\
</div>'
});
// -------------------------------------------------------------------------
function EmployeeList(params) {
var self = this;
self.emps = ko.observableArray(params.emps);
self.canEdit = ko.observable(false);
self.firstnameLastname = function (emp) {
return ko.unwrap(emp.firstName) + ' ' + ko.unwrap(emp.lastName);
};
self.nameFormat = ko.observable(self.firstnameLastname);
self.showModal = function () {
alert("You clicked on " + ko.unwrap(this.displayName));
};
}
// -------------------------------------------------------------------------
ko.applyBindings(new EmployeeList({
emps: [
{firstName: 'First Name-A', lastName: 'Last Name-A'},
{firstName: 'First Name-B', lastName: 'Last Name-B'}
]
}));
.name-container{
padding: 5px;
margin: 2px;
background-color: #cacaca;
border: 1px solid #888;
border-radius: 5px;
}
.name-container span {
margin: 5px;
}
body {
font-family: arial,sans-serif;
font-size: 13px;
}
.action {
cursor: pointer;
color: blue;
text-decoration: underline;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<input type="checkbox" data-bind="checked: canEdit" id="chkEdit">
<label for="chkEdit">Enable editing</label>
<input type="radio" data-bind="value: null, checked: nameFormat" id="chkFmt1">
<label for="chkFmt1">Default format</label>
<input type="radio" data-bind="value: firstnameLastname, checked: nameFormat" id="chkFmt2">
<label for="chkFmt2">Alternative format</label>
<div data-bind='foreach: emps'>
<div data-bind='component: {
name: "emp-box",
params: {emp: $data, formatter: $root.nameFormat, canEdit: $root.canEdit, onEdit: $root.showModal}
}'></div>
</div>
我有一个 knockout component
,它呈现员工的姓名。在这个组件中,我可以通过 callback
函数来改变显示的员工姓名的格式。
但是我遇到了无法更改组件代码的情况。但是我必须添加编辑按钮来显示模态弹出窗口来更新用户信息,如下图所示:
一些我如何使用组件提供的 callback
功能设法显示此编辑按钮。但是我遇到了绑定此按钮的 click event
的问题。
问题是:即使我定义了回调函数 ShowModal
,它也没有被调用。
这是我的代码:
组件注册:
ko.components.register('emp-box', {
viewModel: function(params) {
var self = this;
self.Name = ko.observable();
self.Callback = params.formatCallback;
if(self.Callback !== undefined)
{
self.Name(self.Callback(params.EmpName));
}
else
{
self.Name(params.EmpName.firstName + ', ' + params.EmpName.lastName);
}
},
template: '<div class="name-container"><span data-bind="html: Name"></span></div>'
});
ViewModel
var vm = function() {
var self = this;
self.Emps = [{'Details': {firstName: 'First Name-A', lastName: 'Last Name-A'}},
{'Details': {firstName: 'First Name-B', lastName: 'Last Name-B'}}];
// CALLBACK
self.changeFormat = function(item)
{
return item.firstName + ' - ' + item.lastName + ' <span class="action" data-bind="click: ShowModal">Edit</span>';
}
self.ShowModal = function(item)
{
alert(1);
}
}
ko.applyBindings(new vm());
HTML:
<div data-bind='foreach: Emps'>
<div data-bind='component: {
name: "emp-box",
params: {EmpName: Details, formatCallback: $root.changeFormat}
}'></div>
</div>
工作 Fiddle: Fiddle
如评论中所述,您正试图通过 html
绑定添加更多 "knockout code" 来使视图动态化。这行不通。
在 html
绑定甚至 运行 之前,knockout 一定已经弄清楚了绑定,否则它怎么知道它需要 运行 html
捆绑?一旦绑定阶段完成,它就完成了。因此,您不能以这种方式注入更多的敲除绑定。
Knockout 视图很灵活,只需添加您希望它们具有的所有部分并动态显示它们。在这种情况下,您希望有一个按需显示的 "Edit" 按钮。使用 if
绑定很容易:
<div class="name-container">
<span data-bind="text: displayName"></span>
<span class="action" data-bind="if: canEdit, click: onEdit">Edit</span>
</div>
现在控制它的视图模型需要一个 canEdit
值和一个 onEdit
值,分别是布尔值和函数。这些可以在组件绑定时通过params
来控制。
当您将 displayName 计算为计算并将名称格式化函数存储在可观察对象中时,您甚至可以动态切换名称格式。 运行 下面的代码示例可以看到它的实际效果。
// emp-box.component.js ----------------------------------------------------
function standardNameFormat(emp) {
return ko.unwrap(emp.lastName) + ', ' + ko.unwrap(emp.firstName);
}
ko.components.register('emp-box', {
viewModel: function (params) {
this.emp = params.emp;
this.displayName = ko.computed(function () {
var formatter = ko.unwrap(params.formatter) || standardNameFormat;
return formatter(params.emp);
});
this.canEdit = params.canEdit;
this.onEdit = params.onEdit;
},
template: '<div class="name-container">\
<span data-bind="text: displayName"></span>\
<span class="action" data-bind="if: canEdit, click: onEdit">Edit</span>\
</div>'
});
// -------------------------------------------------------------------------
function EmployeeList(params) {
var self = this;
self.emps = ko.observableArray(params.emps);
self.canEdit = ko.observable(false);
self.firstnameLastname = function (emp) {
return ko.unwrap(emp.firstName) + ' ' + ko.unwrap(emp.lastName);
};
self.nameFormat = ko.observable(self.firstnameLastname);
self.showModal = function () {
alert("You clicked on " + ko.unwrap(this.displayName));
};
}
// -------------------------------------------------------------------------
ko.applyBindings(new EmployeeList({
emps: [
{firstName: 'First Name-A', lastName: 'Last Name-A'},
{firstName: 'First Name-B', lastName: 'Last Name-B'}
]
}));
.name-container{
padding: 5px;
margin: 2px;
background-color: #cacaca;
border: 1px solid #888;
border-radius: 5px;
}
.name-container span {
margin: 5px;
}
body {
font-family: arial,sans-serif;
font-size: 13px;
}
.action {
cursor: pointer;
color: blue;
text-decoration: underline;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<input type="checkbox" data-bind="checked: canEdit" id="chkEdit">
<label for="chkEdit">Enable editing</label>
<input type="radio" data-bind="value: null, checked: nameFormat" id="chkFmt1">
<label for="chkFmt1">Default format</label>
<input type="radio" data-bind="value: firstnameLastname, checked: nameFormat" id="chkFmt2">
<label for="chkFmt2">Alternative format</label>
<div data-bind='foreach: emps'>
<div data-bind='component: {
name: "emp-box",
params: {emp: $data, formatter: $root.nameFormat, canEdit: $root.canEdit, onEdit: $root.showModal}
}'></div>
</div>