subscribeArrayChanged with KnockoutJS

by Shrikrishna Gupta

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
<div data-bind="template: {name: 'testTemplate', foreach: people}"></div>
    
<script id="testTemplate" type="text/html">
    <div class="items" data-bind="text: full() + ' updated at: ' + Date()"></div>
</script>

<button data-bind="click: loadInitialData">Load Initial Data</button>
<button data-bind="click: loadDeleteData">Load Data with Delete</button>
<button data-bind="click: loadAddData">Load Data with Addition</button>

CSS

.items {border-bottom: 1px solid blue;}

JavaScript

ko.observableArray.fn.subscribeArrayChanged = function(addCallback, deleteCallback) {
    var previousValue = undefined;
    this.subscribe(function(_previousValue) {
        previousValue = _previousValue.slice(0);
    }, undefined, 'beforeChange');
    this.subscribe(function(latestValue) {
        var editScript = ko.utils.compareArrays(previousValue, latestValue);
        for (var i = 0, j = editScript.length; i < j; i++) {
            switch (editScript[i].status) {
                case "retained":
                    break;
                case "deleted":
                    if (deleteCallback)
                        deleteCallback(editScript[i].value);
                    break;
                case "added":
                    if (addCallback)
                        addCallback(editScript[i].value);
                    break;
            }
        }
        previousValue = undefined;
    });
};

var data = [
    { id: 0, first: "Not", last: "Updated" },
    { id: 1, first: "Bob", last: "Smith" },
    { id: 2, first: "Jimmy", last: "Jones" },
    { id: 3, first: "Delete", last: "Me" }
];

var deleteData = [
    { id: 0, first: "Not", last: "Updated" },
    { id: 1, first: "Bob", last: "Smith" },
    { id: 2, first: "Jimmy", last: "Jones" }
];

var addData = [
    { id: 0, first: "Not", last: "Updated" },
    { id: 1, first: "Bob", last: "Smith" },
    { id: 2, first: "Jimmy", last: "Jones" },
    { id: 3, first: "Delete", last: "Me" },
    { id: 4, first: "Add", last: "Me" }
];

var Person = function(data) {
    this.id = data.id;
    this.first = ko.observable(data.first);
    this.last = ko.observable(data.last);
    this.full = ko.computed(function() {
        return this.first() + " " + this.last();
    }, this);        
};


var dataMappingOptions = {
    key: function(data) {
        return ko.utils.unwrapObservable(data.id);        
    },
    create: function(options) {
        return new Person(options.data);
    }    
};

var viewModel = {
   ...