簡體   English   中英

如何使用Knockout可觀察數組來處理jQuery對話框

[英]How do you get a Knockout observable array to work with a jQuery dialog

我是javascript和淘汰賽的新手。 上周我花了一整天時間嘗試使用jquery對話框進行淘汰觀察,以便編輯和向項目數組添加新值。 我很接近,但最終無法讓它完全正常工作。

我的問題有兩個部分。

我創建了一個完美重新創建問題的JSFiddle。

這個小提琴表明我可以編輯現有的折扣代碼。

我還可以添加折扣代碼。 但是,當我添加或編輯第二個(或第三個等)NEW折扣代碼時,所有新的折扣代碼都會被編輯。 它確實添加了新的一個,但第一個新的獲得與第二個新項目相同的值。

這是小提琴......

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

第一個問題。 你能讓這個小提琴上班嗎? 我認為修復可能很簡單。 我需要改變什么。

第二個問題。 我知道這個小提琴的例子並沒有充分利用敲除綁定。

例如,我正在設置然后使用vm.CurrentDiscountCode observable添加或編輯。 但是,我知道knockout有一個$ data綁定上下文,可以而且應該使用它。 我永遠無法弄清楚如何讓它發揮作用。 我想出了如何使用$ data上下文編輯現有項目,但無法弄清楚如何添加新項目。

總結一下。
讓小提琴工作的BARE最小變化是什么? 什么是OPTIMAL方法來實現這個目標?

這是小提琴的代碼。

編輯小提琴現在正在運作。 使用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;
}

在此先感謝您的幫助。

賽斯

回答你的問題:“實現這項工作的最佳方式是什么?”

我不會從自定義綁定處理程序開始。 從具有明確定義的方法的viewModel開始(大多數方法)。 在您的方法中,只需手動執行jquery即可打開和關閉對話框。 獲取工作第一。 一旦你有了它,你就可以把它移回一個bindingHandler,如果你認為它是值得的。

改變這個......

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/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM