简体   繁体   中英

Knockout Add and Edit observableArray Conflict

I have an observableArray which is displayed in a table using foreach binding where values are displayed inside textboxes. Now what I want to do is to add an edit link on each row which enables/disables the readonly state of the corresponding textbox in its row. I can do it, but the way I did it messed up my add new line (push) functionality.

Here is a fiddle of my code.

Try to delete a line then add it again by selecting it in the dropdown list, the edit link disappears as well as the value.

Any help will be greatly appreciated! Thank you.

So here's my HTML:

<table class="input-group" >
    <tbody data-bind="foreach: loanDeductions">
        <tr>
            <td><strong data-bind='text: deductionName'></strong></td>
            <td><input class="deductionCode form-control" style="text-align: right" data-bind='value: amount, valueUpdate: "afterkeydown", attr: { "readonly": getreadonlyState() }' /></td>
            <td><a href='#' data-bind='click: $parent.removeLine'>Delete</a></td>
            <td><a href="javascript:void(0);" data-bind="click: $parent.readonly"><span data-bind="text: linkText"></span></a></td>
        </tr>
    </tbody>        
</table>
<table>
    <tr>
        <td colspan="3"><select data-bind="options: loanDeductionsList(), optionsText: 'deductionName', optionsCaption: 'Choose a deduction..', value: selectedDeduction"></select></td>
    </tr>
</table>

Now here is my script:

var deductionLine = function (deductionID, deductionName, amount) {
    self = this;
    self.deductionID = ko.observable(deductionID);
    self.deductionName = ko.observable(deductionName);
    self.amount = ko.observable(formatCurrency(amount));
    self.getreadonlyState = ko.observable('readonly');
    self.linkText = ko.computed(function () {
        return this.getreadonlyState() == 'readonly' ? "Edit" : "Stop Edit";
    }, self);
};

var deductionList = function (deductionID, deductionName, amount) {
    self = this;
    self.deductionID = ko.observable(deductionID);
    self.deductionName = ko.observable(deductionName);
    self.amount = ko.observable(formatCurrency(amount));
};

function LoanDeductions(deductions) {
    var self = this;
    self.loanDeductions = ko.observableArray(ko.utils.arrayMap(deductions, function (deduction) {
        return new deductionLine(deduction.deductionID, deduction.deductionName, deduction.amount)
    }));
    self.loanDeductionsList = ko.observableArray(ko.utils.arrayMap(deductions, function (deduction) {
        return new deductionList(deduction.deductionID, deduction.deductionName, deduction.amount)
    }));

    self.selectedDeduction = ko.observable();

    //edit link

    self.readonly = function () {
        if (BossBaU) {
            if (this.getreadonlyState()) {
                this.getreadonlyState(undefined);
            }
            else {
                this.getreadonlyState('readonly');
            }
        }
        else alert('Access denied!');
    }

    // adds deduction 
    self.selectedDeduction.subscribe(function (data) {
        var match = ko.utils.arrayFirst(self.loanDeductions(), function (deduction) {
            return deduction.deductionID() === data.deductionID();
        });
        if (match) {
            alert(data.deductionName() + ' already exists!');
            self.showAddDeduc(false);
        } else {
            self.loanDeductions.push({
                deductionID: data.deductionID,
                deductionName: data.deductionName,
                amount: data.amount,
            });
            self.showAddDeduc(false);
        }
    });

    //delete deduction
    self.removeLine = function (line) { self.loanDeductions.remove(line) };

};

var viewModel = new LoanDeductions(@Html.Raw(Model.CRefLoansDeductions2.ToJson()));
$(document).ready(function () {
    ko.applyBindings(viewModel);
});

I found the cause of the problem, I had to mirror every changes I made with my observableArray to my list.

var deductionLine = function (deductionID, deductionName, amount) {
    self = this;
    self.deductionID = ko.observable(deductionID);
    self.deductionName = ko.observable(deductionName);
    self.amount = ko.observable(amount);
    self.getreadonlyState = ko.observable('readonly');
    self.linkText = ko.computed(function () {
        return this.getreadonlyState() == 'readonly' ? "Edit" : "Stop Edit";
    }, self);
};

var deductionList = function (deductionID, deductionName, amount) {
    self = this;
    self.deductionID = ko.observable(deductionID);
    self.deductionName = ko.observable(deductionName);
    self.amount = ko.observable(amount);
    self.getreadonlyState = ko.observable('readonly');
    self.linkText = ko.computed(function () {
        return this.getreadonlyState() == 'readonly' ? "Edit" : "Stop Edit";
    }, self);
};

Here's the fiddle in case anyone bump into a similar issue.

In the subscribe handler, self.selectedDeduction.subscribe , you're adding an object to the list of loanDeductions when you should be adding a new instance of deductionLine just as you do when you declare self.loanDeductions .

Or to put it another way, self.loadDeductions is an observableArray of deductionLine instances, to which you then add an object with three properties.

Change that subscribe handler to push a new deductionLine(...) and you'll see the difference.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM