我是KnockoutJS的新手。我想知道是否有更好的方法来完成下面的功能。使用KnockoutJS使对象的属性可单独编辑
对象的属性在表格行中显示为文本。我可以单独单击每个文本段以使文本框出现,以便我可以编辑文本。请注意,与对象相关的其他属性不可编辑。一次只能编辑一个属性。为此,在KO映射期间,我实际上用具有两个属性的对象覆盖每个属性:保存原始属性值的'value'属性和用于跟踪文本框可见性的'hasFocus'属性。
这里是一个JSFiddle来显示我目前如何编程。一定要点击商品名称和价格才能看到文本框出现。
进一步说明
我有其中每行代表一个TransactionItem的表。
在起始状态下,每个字段都是文本。点击后,文本消失并出现文本框。当文本框失去焦点时,文本框消失并且修改的文本重新出现。
下列步骤显示我做了什么做到这一点:
使用KO映射插件(在这个例子中 '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) };
例如,“姓名”属性成为对象名称:{值:' Item1',hasFocus:false}。
在HTML中,数据绑定每个属性的'hasFocus'以控制何时显示/隐藏文本/文本框。
当单击文本时,“hasFocus”属性设置为true,这将隐藏的文本,显示文本框。
- 当文本框模糊时,“hasFocus”属性被设置为假,隐藏文本框,并显示文本。
我想知道是否有更好的方法来完成这个功能。我走偏了轨道吗?谢谢!代码
较大的片段:
<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>
您的解决方案效果很好!是否有方法遍历每个属性(例如名称,价格等),以便我不必将“Name”或“Price”明确硬编码为编辑函数的参数?如果是这样,我可以在模板中放入一段HTML代码,并让该模板为每个属性呈现数据绑定代码。 – JerryM
下面是如何做到这一点的示例:http://jsfiddle.net/antishok/a2EPT/8/ – antishok
非常好!谢谢! – JerryM