Dawood Awan
Dawood Awan

Reputation: 7348

Knockout Js update ViewModel when data attribute is updated

I am using jQuery UI Sortable with KnockoutJS ViewModel.

I have an array inside a ViewModel, which is used to Display a Div, and User can sort those divs by jQueryUI Sortable.

I have created a Similar scenario in a JSFiddle: http://jsfiddle.net/swscgvvh/2/

ko.applyBindings({
    items: [{
        ThisText: 'Bert',
        index: 1
    }, {
        ThisText: 'Charles',
        index: 2
    }, {
        ThisText: 'Denise',
        index: 3
    }]
});


$(function () {
    $(".sortable").sortable({
        forceHelperSize: true,
        revert: true,
        stop: function (event, ui) {
            var sorter = $(this);
            var sortables = sorter.children();

            sortables.each(function (i) {
                // HERE I Update the data-id attribute
                $(sortables[i]).attr('data-id', i + 1);
            });
        }
    });
});

On this line of the Code: $(sortables[i]).attr('data-id', i + 1);

I am updating the attr: data-id, of the div. but this is not taking affect in the ViewModel.

If you do an Inspect Element on the Div, the data-id=3 when Charles is moved to 3rd Position.

enter image description here

Upvotes: 2

Views: 688

Answers (2)

Artem
Artem

Reputation: 3700

First thing - if you will change attribute this will not update underlying ViewModel (and this is correct, idea to update attribite from code to change ViewModel is against concept of MVVM pattern - in your code you should change ViewModel, and knockout will update View for you).

Regarding yor example, you have 2 issues:

index is plain integer, you should define it as observable, i.e.

index: ko.observable(1)

Instead of updating data-id, you should use ko.dataFor utility function, and update ViewModel:

ko.dataFor(this).index(i+1);

Whole sample:

fiddle

ko.applyBindings({
    items: ko.observableArray([{
        ThisText: 'Bert',
        index: ko.observable(1)
    }, {
        ThisText: 'Charles',
        index: ko.observable(2)
    }, {
        ThisText: 'Denise',
        index: ko.observable(3)
    }])
});


$(function () {
    $(".sortable").sortable({
        forceHelperSize: true,
        revert: true,
        stop: function (event, ui) {
            var sorter = $(this);
            var sortables = sorter.children();

            sortables.each(function (i) {
                // HERE I Update the data-id attribute
                ko.dataFor(this).index(i+1);
            });
        }
    });
});

NOTE: Also consider using plugin knockout-dragdrop, it supports sorting as well - see examples - it is much better than mixing JQuery UI Sortable with Knockout.

Upvotes: 2

freethinker
freethinker

Reputation: 2435

This because your jquery script is running before the html Dom is ready. You can put your anonimous function inside "setTimeout". This is bad practice but will work

Upvotes: 0

Related Questions