如何使用Knockout可观察数组来处理jQuery对话框

时间:2015-02-23 17:26:14

标签: javascript jquery knockout.js knockout-2.0

我是javascript和淘汰赛的新手。上周我花了一整天时间尝试使用jquery对话框进行淘汰观察,以便编辑和向项目数组添加新值。我接近了,但最终还是无法正常工作。

我的问题分为两部分。

我创建了一个完全重新创建问题的JSFiddle。

这个小提琴表明我可以编辑现有的折扣代码。

我还可以添加折扣代码。但是,当我添加或编辑第二个(或第三个等)NEW折扣代码时,所有新的折扣代码都会被编辑。它确实添加了新的一个,但第一个新的获得与第二个新项目相同的值。

这是小提琴......

http://jsfiddle.net/sethspearman/2jxtpw7s/28/

第一个问题。 你能让这个小提琴上班吗?我认为修复可能很简单。我需要改变什么。

第二个问题。 我知道这个小提琴的例子并没有充分利用敲除绑定。

例如,我正在设置然后使用vm.CurrentDiscountCode observable添加或编辑。但是,我知道knockout有一个$ data绑定上下文,可以而且应该使用它。我永远无法弄清楚如何让它发挥作用。我想出了如何使用$ data上下文编辑现有项目,但无法弄清楚如何添加新项目。

总结一下。
让小提琴工作的BARE最小变化是什么? 什么是最佳的工作方式?

这是小提琴的代码。

编辑小提琴现在正在运作。使用HTTPS时无效。

HTML

<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>&nbsp;</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>

JAVASCRIPT

//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);

CSS

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;
}

提前感谢您的帮助。

赛斯

2 个答案:

答案 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)寻求解决方案

看到一个大大简化的版本......

http://jsfiddle.net/gh6mzrxp/34/