我是javascript和淘汰赛的新手。上周我花了一整天时间尝试使用jquery对话框进行淘汰观察,以便编辑和向项目数组添加新值。我接近了,但最终还是无法正常工作。
我的问题分为两部分。
我创建了一个完全重新创建问题的JSFiddle。
这个小提琴表明我可以编辑现有的折扣代码。
我还可以添加折扣代码。但是,当我添加或编辑第二个(或第三个等)NEW折扣代码时,所有新的折扣代码都会被编辑。它确实添加了新的一个,但第一个新的获得与第二个新项目相同的值。
这是小提琴......
http://jsfiddle.net/sethspearman/2jxtpw7s/28/
第一个问题。 你能让这个小提琴上班吗?我认为修复可能很简单。我需要改变什么。
第二个问题。 我知道这个小提琴的例子并没有充分利用敲除绑定。
例如,我正在设置然后使用vm.CurrentDiscountCode observable添加或编辑。但是,我知道knockout有一个$ data绑定上下文,可以而且应该使用它。我永远无法弄清楚如何让它发挥作用。我想出了如何使用$ data上下文编辑现有项目,但无法弄清楚如何添加新项目。
总结一下。
让小提琴工作的BARE最小变化是什么?
什么是最佳的工作方式?
这是小提琴的代码。
编辑小提琴现在正在运作。使用HTTPS时无效。
<body>
<h1>Discount Codes Test</h1>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/knockout-debug.js"></script>
<script id="editTmpl" type="text/html">
<div>
<ul>
<li>
<div class="inline-item">
<input type="hidden" name="codeId" id="codeId" data-bind="value: $parent.currentId" />
</div>
</li>
<li>
<div class="inline-item w4 right-text">
<span class="label auto">Title</span>
</div>
<div class="inline-item">
<input type="text" name="description" id="description" data-bind="value: $parent.currentDescription" />
</div>
</li>
<li>
<div class="inline-item w4 right-text">
<span class="label auto">Code</span>
</div>
<div class="inline-item">
<input type="text" name="discountCode" id="discountCode" data-bind="value: $root.currentCode, keypressvalidator: $root.currentCode, visible: $parent.currentItemIsNew() == true" />
<label data-bind="text: $parent.currentCode, visible: $parent.currentItemIsNew() == false"></label>
</div>
</li>
<li>
<div class="inline-item w4 right-text">
<span class="label auto">Discount Amount</span>
</div>
<div class="inline-item">
<input type="text" name="amount" id="amount" data-bind="value: $root.currentDiscountAmount, visible: $parent.currentItemIsNew() == true" />
<label data-bind="text: $parent.currentDiscountAmount, visible: $parent.currentItemIsNew() == false"></label>
</div>
</li>
<li>
<div class="inline-item w4 right-text">
<span class="label auto">Max Usages</span>
</div>
<div class="inline-item">
<input type="text" name="maxUsages" id="maxUsages" data-bind="value: $root.currentMaxUsages, visible: $parent.currentItemIsNew() == true" />
<label data-bind="text: $parent.currentMaxUsages, visible: $parent.currentItemIsNew() == false"></label>
</div>
</li>
<li>
<div class="inline-item w4 right-text">
<span class="label auto">Number of Usages</span>
</div>
<div class="inline-item">
<label data-bind="text: $parent.currentNumberOfUsages"></label>
</div>
</li>
<li>
<div class="inline-item w4 right-text">
<span class="label auto">Active</span>
</div>
<div class="inline-item">
<input type="checkbox" name="isActive" id="isActive" data-bind="checked: $root.currentActive" />
</div>
</li>
</ul>
<button data-bind="jqButton: {}, click:$root.accept">Accept</button>
<button data-bind="jqButton: {}, click:$root.cancel">Cancel</button>
</div>
</script>
<!--
**************************************
-->
<div>
<fieldset data-regmode="printed">
<div>
<h3>Add or Edit Discount Codes</h3>
<div id="discountCodes"></div>
<table>
<thead>
<tr>
<th>Title</th>
<th>Code</th>
<th>DiscountAmount</th>
<th>MaxUsages</th>
<th>Active</th>
<th> </th>
</tr>
</thead>
<tbody data-bind="foreach: DiscountCodes">
<tr style="cursor: pointer">
<td data-bind="text: Description"></td>
<td data-bind="text: Code"></td>
<td data-bind="text: DiscountAmount"></td>
<td data-bind="text: MaxUsages"></td>
<td data-bind="text: NumberOfUsages"></td>
<td data-bind="text: Active"></td>
<td><button type="button" data-bind="click: $root.editDiscountCode">Edit</button></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="6"><button type="button" id="create-code" data-bind="click: createDiscountCode">Add New</button></td>
</tr>
</tfoot>
</table>
</div>
</fieldset>
</div>
<div id="details" data-bind="jqDialog: { autoOpen: false, resizable: false, modal: true, height: 400, width:350, title:'Add/Edit Discount Code' }, template: { name: 'editTmpl', data: currentDiscountCode, if: currentDiscountCode }, openDialog: currentDiscountCode"></div>
</body>
//custom binding to initialize a jQuery UI dialog
ko.bindingHandlers.jqDialog = {
init: function (element, valueAccessor) {
var options = ko.utils.unwrapObservable(valueAccessor()) || {};
//handle disposal
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).dialog("destroy");
});
//dialog is moved to the bottom of the page by jQuery UI. Prevent initial pass of ko.applyBindings from hitting it
setTimeout(function () {
$(element).dialog(options);
}, 0);
}
};
var currentDialog;
//custom binding handler that opens/closes the dialog
ko.bindingHandlers.openDialog = {
update: function (element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
if (typeof value == 'undefined') {
return;
}
currentDialog = $(element);
if (value) {
$(element).dialog("open");
} else {
$(element).dialog("close");
}
}
};
//custom binding to initialize a jQuery UI button
ko.bindingHandlers.jqButton = {
init: function (element, valueAccessor) {
var options = ko.utils.unwrapObservable(valueAccessor()) || {};
//handle disposal
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).button("destroy");
});
$(element).button(options);
}
};
var vm = {};
var DiscountCode = function (description, code, discountAmount, maxUsages, numberOfUsages, active) {
this.Id = ko.observable(0);
this.Description = ko.observable(description)
this.Code = ko.observable(code);
this.DiscountAmount = ko.observable(discountAmount);
this.MaxUsages = ko.observable(maxUsages);
this.NumberOfUsages = ko.observable(numberOfUsages);
this.Active = ko.observable(active);
}
var code1 = new DiscountCode('Give a 25% discount','DISC25',25, 5, 0, true);
var code2 = new DiscountCode('Give a 10% discount','DISC10',10,20, 0, true);
var code3 = new DiscountCode('Give a 5% discount' ,'DISC05', 5,30, 0, true);
var discountCodes = ko.observableArray([code1,code2,code3]);
vm.DiscountCodes = discountCodes;
vm.currentId = ko.observable();
vm.currentDescription = ko.observable();
vm.currentCode = ko.observable().extend({ codeConverter: 0 });
vm.currentDiscountAmount = ko.observable();
vm.currentMaxUsages = ko.observable();
vm.currentNumberOfUsages = ko.observable();
vm.currentActive = ko.observable();
vm.currentDiscountCode = ko.observable();
vm.revertableDiscountCode = ko.observable();
vm.currentItemIsNew = ko.observable(false);
vm.editDiscountCode = function (discountCodeToEdit) {
vm.revertableDiscountCode(discountCodeToEdit);
vm.currentDiscountCode(discountCodeToEdit);
vm.currentItemIsNew(false);
setCurrent(discountCodeToEdit);
};
vm.createDiscountCode = function() {
vm.currentDiscountCode(new DiscountCode("", "", 0, 0, 0, true));
vm.currentItemIsNew(true);
setCurrent(vm.currentDiscountCode());
};
function setCurrent(discountCode) {
vm.currentId(discountCode.Id());
vm.currentDescription (discountCode.Description());
vm.currentCode(discountCode.Code());
vm.currentDiscountAmount ( discountCode.DiscountAmount());
vm.currentMaxUsages(discountCode.MaxUsages());
vm.currentNumberOfUsages(discountCode.NumberOfUsages());
vm.currentActive (discountCode.Active());
}
vm.removeDiscountCode = function(discountCodeToRemove) {
vm.DiscountCodes.remove(discountCodeToRemove);
}
vm.accept = function() {
var currentItem = vm.currentDiscountCode();
if (vm.currentItemIsNew()) {
vm.DiscountCodes.push({
Id: vm.currentId,
Description: vm.currentDescription,
Code: vm.currentCode,
DiscountAmount: vm.currentDiscountAmount,
MaxUsages: vm.currentMaxUsages,
NumberOfUsages: vm.currentNumberOfUsages,
Active: vm.currentActive
});
vm.currentItemIsNew(false);
} else {
currentItem.Id(vm.currentId());
currentItem.Description(vm.currentDescription());
currentItem.Code(vm.currentCode());
currentItem.DiscountAmount(vm.currentDiscountAmount());
currentItem.MaxUsages(vm.currentMaxUsages());
currentItem.NumberOfUsages(vm.currentNumberOfUsages());
currentItem.Active(vm.currentActive());
}
vm.currentDiscountCode("");
}
vm.cancel = function() {
vm.currentDiscountCode(vm.revertableDiscountCode);
currentDialog.dialog("close");
vm.currentDiscountCode("");
}
ko.applyBindings(vm);
body {
font-size: 62.5%;
}
label, input {
display: block;
}
input.text {
margin-bottom: 12px;
width: 95%;
padding: .4em;
}
fieldset {
padding: 0;
border: 0;
margin-top: 25px;
}
h1 {
font-size: 1.2em;
margin: .6em 0;
}
div#users-contain {
width: 350px;
margin: 20px 0;
}
div#users-contain table {
margin: 1em 0;
border-collapse: collapse;
width: 100%;
}
div#users-contain table td, div#users-contain table th {
border: 1px solid #eee;
padding: .6em 10px;
text-align: left;
}
.ui-dialog .ui-state-error {
padding: .3em;
}
.validateTips {
border: 1px solid transparent;
padding: 0.3em;
}
提前感谢您的帮助。
赛斯
答案 0 :(得分:0)
回答您的问题:&#34;实现这项工作的最佳方式是什么?&#34;
我不会从自定义绑定处理程序开始。从具有明确定义的方法的viewModel开始(大多数方法)。在您的方法中,只需手动执行jquery即可打开和关闭对话框。 首先工作。一旦你有了它的工作,你可以把它移回一个bindingHandler,如果你认为它是值得的。
答案 1 :(得分:0)
改变这个......
if (vm.currentItemIsNew()) {
vm.DiscountCodes.push({
Id: vm.currentId,
Description: vm.currentDescription,
Code: vm.currentCode,
DiscountAmount: vm.currentDiscountAmount,
MaxUsages: vm.currentMaxUsages,
NumberOfUsages: vm.currentNumberOfUsages,
Active: vm.currentActive
});
到此......
if (vm.currentItemIsNew()) {
vm.DiscountCodes.push(new DiscountCode(
vm.currentDescription(),
vm.currentCode(),
vm.currentDiscountAmount(),
vm.currentMaxUsages(),
vm.currentNumberOfUsages(),
vm.currentActive()
));
......做了伎俩 HT向Ryan Niemeyer(knockmeout.com)寻求解决方案
看到一个大大简化的版本......