Search code examples
jqueryknockout.jsko.observablearray

observableArray feature in jQuery


Using both knockout.js & jQuery.

I'm trying to utilise the observableArray in jQuery. The table is bound by such an Array - products. Clicking on 'Edit' in any row, will get the cell values and fill them in the respective textboxes to be modified.

Requirement : When 'Update' is clicked, it will update the 'products' array with the new values and inturn reflect the changes in the table. Is this possible. Is it a right approach.

The code I tried isn't working.

I cannot have each property as observable.There would be numerous rows and this is causing performance issues.

http://jsfiddle.net/HXZ2u/4/

$(document).on("click", "#btnUpd", function () {
    var p = $("#txtName").val();
    var q = $("#txtQty").val();

    ViewModel.products.replace(products()[index], {
        pname: p,
        qty: q
    });
});

Solution

  • Woa, hold on there!

    You are asking a lot of things at once, some perhaps not a good fit for SO. In your question I see at least these:

    1. Is [my approach] possible?
    2. Is it a right approach?
    3. My [the fiddle?] isn't working.
    4. I cannot have each property as observable [, or can I?].

    Only the third question is really a good fit for SO, and answerable. First things first though.

    Is [this approach] possible?
    Yeah, I guess you could make this work.

    Is it a right approach?
    Nope, not in my opinion. You're fighting KO instead of using it. Hardly ever do I need to use jQuery (or at least not its DOM manipulation features), and when I thought I needed them it was because I didn't know or understand about a feature of KO. Possible exception to the DOM-bit of my remark could be hooking up to certain jQuery plugins like a datepicker, or jQuery effects.

    What is wrong with the fiddle?
    You have several problems in your fiddle:

    • Product's properties aren't observable, which is necessary for the View to get updated;
    • You're adding +1 to the index in the view, but the index actually will be zero-based;
    • You're referencing the ViewModel constructor function directly in the on click handler, instead of an instance of the view model;
    • You're not digging up the index in the on click handler;

    With all of that fixed, your code would look like this:

    function Product(Name, Qty) {
        var self = this;
        self.pname = ko.observable(Name);
        self.qty = ko.observable(Qty);
    }
    
    var ViewModel = function () {
        var self = this;
        self.products = ko.observableArray([new Product('Mobile', 2),
        new Product('Books', 5)]);
    };
    
    /*-----------jQuery------------------*/
    var index;
    $(document).on("click", ".edit", function () {
        row = $(this).closest("tr");
        cols = row.find("td");
        index = $(this).parent().parent().index();
        var arr = [];
        $.each(cols, function (index, item) {
            arr.push(item.innerHTML);
        });
        $("#txtId").val(arr[1]);
        $("#txtName").val(arr[2]);
        $("#txtQty").val(arr[3]);
    });
    
    var vm = new ViewModel();
    
    $(document).on("click", "#btnUpd", function () {
        var index = $("#txtId").val();
        var p = $("#txtName").val();
        var q = $("#txtQty").val();
    
        var product = vm.products()[index];
        product.pname(p);
        product.qty(q);
    });
    
    ko.applyBindings(vm);
    

    With the only update to the view being that the index became zero based. See this working in an updated fiddle.

    I cannot use KO properties all around because of performance issues. I find this very hard to believe. Are you very sure? Are you sure a jQuery version won't also have problems (as in: have you tested this)? KO can be pushed quite far in terms of performance, and when you reach its limits you probably have other/bigger design problems in your app.

    I'd recommend trying to not use jQuery at all for as much as possible if you're to get the most out of KO. As your code stands, you'd be getting little benefit from it anyways.