Search code examples
twitter-bootstrapknockout.jsknockout-validationx-editable

Knockout X-Editable success handler is not called


I have a column in a table with knockout x-editable bind values. After page load and as a result of ko binding the success handler is called for each row (which is fine, I can avoid that). But once the page is set up, and I go ahead and change a value (set any of the row's employeeId to a 7 digit number), the success handler is not called any more. See this fiddle with opened console log:

http://jsfiddle.net/csabatoth/y3rfe6Lw/6/

HTML:

<table style="table table-striped">
    <thead>
        <tr>
            <td>First Name</td>
            <td>Last Name</td>
            <td>Employee ID</td>
        </tr>
    </thead>
    <tbody data-bind="foreach: candidates">
        <tr>
            <td><span data-bind="text: firstName"></span></td>
            <td><span data-bind="text: lastName"></span></td>
            <td><span data-bind="editable: employeeId, editableOptions: { validate: $root.validateEmployeeId, success: $root.persistEmployeeId($data) }"></span></td>
        </tr>
    </tbody>
</table>

JS:

$(document).ready(function () {
    function AppViewModel() {
        var self = this;

        self.validateEmployeeId = function (value) {
            if (value == null || !value.match(/^\d{7}$/))
                return 'Invalid EmployeeID';
        }

        self.persistEmployeeId = function (data) {
            console.log(data.employeeId);
        }

        self.candidates = ko.observableArray([
            { firstName: "John", lastName: "Dow", employeeId: 1001, applicantId: 1 },
            { firstName: "Jane", lastName: "Doe", employeeId: 1002, applicantId: 2 },
            { firstName: "Foo", lastName: "Bar", employeeId: 1003, applicantId: 3 }
        ]);
    }

    // Activates knockout.js
    ko.applyBindings(new AppViewModel());

});

I need to persist the data change though. I tried to workaround this problem by making employeeId ko.observable and subscribing to the change event of it. But with the subscribe I only receive the newValue as a parameter. I would need the data row, and the applicantId from it. The employeeId might not be unique, and I need to the persistence API call needs applicantId and employeeId.

How can I solve this?


Solution

  • I couldn't do what you were trying to do with the success binding (I don't think you can do it) but I instead just used Knockout with a subscribe.

    Declare Applicant ViewModel as we need employeeId to be an observable to subscribe to:

    var Applicant = function (model) {
        var self = this;
    
        self.firstName = model.firstName;
        self.lastName = model.lastName;
        self.employeeId = ko.observable(model.employeeId);
        self.applicantId = model.applicantId;
    
        self.employeeId.subscribe(function (newValue) {
            console.debug('Applicant ' + self.applicantId + ' now has employeeId: ' + newValue);
        });
    }
    

    Change the candidates arrray population to use the Applicant ViewModel instead:

    var candidates = [
        new Applicant({ firstName: "John", lastName: "Dow", employeeId: 1001, applicantId: 1 }),
        new Applicant({ firstName: "Jane", lastName: "Doe", employeeId: 1002, applicantId: 2 }),
        new Applicant({ firstName: "Foo", lastName: "Bar", employeeId: 1003, applicantId: 3 })
    ];
    
    self.candidates = ko.observableArray(candidates);
    

    JsFiddle