我是KnockoutJS的新手。我想知道是否有更好的方法来完成下面的功能。
对象的属性在表格行中显示为文本。我可以单独单击每个文本范围以显示文本框,以便我可以编辑文本。请务必注意,与对象相关的其他属性不可编辑。一次只能编辑一个属性。为了实现这一点,在KO Mapping期间,我实际上用一个具有两个属性的对象覆盖每个属性:一个'value'属性,用于保存原始属性的值,以及一个'hasFocus'属性,用于跟踪文本框的可见性
这是一个JSFiddle来展示我目前如何编程。请务必点击项目名称和价格以查看文本框。
进一步说明
我有一个表,其中每一行代表一个TransactionItem。
在开始状态下,每个字段都是文本。单击时,文本消失并显示文本框。当文本框失去焦点时,文本框将消失,修改后的文本会重新出现。
以下步骤显示了我为实现此目的所做的工作:
使用KO Mapping插件(在此示例中为'myData')映射服务器中的数据,
var myData = [
{
TransactionItems: [
{
Name: "Item1",
Price: "1.00"
},
{
Name: "Item2",
Price: "2.00"
},
{
Name: "Item3",
Price: "3.00"
},
]},
];
var mappingOptions = {
'TransactionItems': {
create: function (options) {
return new TransactionItem(options.data);
}
}
}
var viewModel = {};
var self = viewModel;
viewModel.transactions = ko.mapping.fromJS(myData, mappingOptions);
ko.applyBindings(viewModel);
在TransactionItems构造函数中,获取TransactionItem属性的当前值('name','price'),并将它们存储在临时变量中。使用新对象覆盖属性。这些新对象包含两个值:原始属性的“值”和新的“hasFocus”属性
//Grab the current values of the properties
var itemValue = this.Name();
var priceValue = this.Price();
//Recreate properties as objects, give them a 'hasFocus' property
this.Name = { value: itemValue, hasFocus: ko.observable(false)};
this.Price = { value: priceValue, hasFocus: ko.observable(false) };
例如,'name'属性成为对象Name:{value:'Item1',hasFocus:false}。
在HTML中,数据绑定每个属性的'hasFocus'以控制何时显示/隐藏文本/文本框。
单击文本时,'hasFocus'属性设置为true,这将隐藏文本,并显示文本框。
我想知道是否有更好的方法来完成此功能。我离开了轨道吗?谢谢!
更大的代码片段:
<table>
<thead>
<tr>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<!-- ko foreach: transactions -->
<!-- ko template: { name: 'listItems', foreach: TransactionItems } -->
<!-- /ko -->
<!-- /ko -->
</tbody>
</table>
<script type="text/html" id="listItems">
<tr>
<td>
<!-- Either show this -->
<span data-bind="visible: !Name.hasFocus(),
text: Name.value,
click: editItem.bind($data, Name)"></span>
<!-- Or show this -->
<input data-bind="visible: Name.hasFocus,
value: Name.value,
hasfocus: Name.hasFocus,
event: {
focus: editItem.bind($data, Name),
blur: hideItem.bind($data, Name)
}"
/><!-- end input -->
</td>
<td>
<!-- Either show this -->
<span data-bind="visible: !Price.hasFocus(),
text: Price.value, click: editItem.bind($data, Price)"></span>
<!-- Or show this -->
<input data-bind="visible: Price.hasFocus,
value: Price.value,
hasfocus: Price.hasFocus,
event: {
focus: editItem.bind($data, Price),
blur: hideItem.bind($data, Price)
}"
/><!--input end -->
</td>
</tr>
</script>
<!-- END OF HTML -->
<script >
function TransactionItem(data) {
ko.mapping.fromJS(data, {}, this);
this.editable = ko.observable(false);
this.hasFocus = ko.observable(false);
//Grab the current values of the properties
var itemValue = this.Name();
var priceValue = this.Price();
//Recreate properties as objects, give them a 'hasFocus' property
this.Name = { value: itemValue, hasFocus: ko.observable(false)};
this.Price = { value: priceValue, hasFocus: ko.observable(false) };
this.editItem = function (objProperty) {
this.editable(true);
objProperty.hasFocus(true);
}
this.hideItem = function (objProperty) {
this.editable(false);
objProperty.hasFocus(false);
}
}
//MAPPING
var mappingOptions = {
'TransactionItems': {
create: function (options) {
return new TransactionItem(options.data);
}
}
}
//DATA
var myData = [
{
TransactionItems: [
{
Name: "Item1",
Price: "1.00"
},
{
Name: "Item2",
Price: "2.00"
},
{
Name: "Item3",
Price: "3.00"
},
]},
];
//VIEWMODEL
var viewModel = {};
var self = viewModel;
viewModel.transactions = ko.mapping.fromJS(myData, mappingOptions);
ko.applyBindings(viewModel);
</script>
答案 0 :(得分:1)
我认为在根VM对象中使用字段来指定当前正在编辑哪个项目/字段并使用该字段更简单,而不是为每个项目和字段的编辑状态分别设置单独的可观察对象。您可以放置辅助函数在您的虚拟机中,以帮助您在绑定中处理它。
为了处理输入模糊,我处理了文档元素(或任何合适的元素)的点击,并确保点击事件不会从可编辑元素中冒出来。我使用clickBubble
绑定做到了这一点,但使用jQuery(或替代方法)可能更容易。
JSFiddle:http://jsfiddle.net/antishok/a2EPT/7/
JS:
function TransactionItem(data) {
ko.mapping.fromJS(data, {}, this);
}
function ViewModel(data) {
var self = this;
this.transactions = ko.mapping.fromJS(data, mappingOptions);
this.editedItem = ko.observable();
this.editedField = ko.observable();
this.isEdited = function (item, field) {
return self.editedItem() === item && self.editedField() === field;
}
this.editItem = function (field, item) {
self.editedItem(item);
self.editedField(field);
}
this.stopEditing = function() {
self.editItem(undefined, undefined);
}
}
var viewModel = new ViewModel(myData);
ko.applyBindings(viewModel);
ko.utils.registerEventHandler(document, 'click', function(event) {
viewModel.stopEditing();
});
HTML:
<td>
<!-- Either show this -->
<span data-bind="visible: !$root.isEdited($data, 'Name'),
text: Name,
click: $root.editItem.bind($data, 'Name'), clickBubble: false"></span>
<!-- Or show this -->
<input data-bind="visible: $root.isEdited($data, 'Name'),
value: Name,
hasfocus: $root.isEdited($data, 'Name'),
click: function(){}, clickBubble: false"
/><!-- end input -->
</td>