Isotope.js with Knockout.js

isotope works fine at first being able to sort and remove items just fine. But the second new items are added then isotope falls apart.

by evanlarsen

HTML

<script src="https://github.com/SteveSanderson/knockout/raw/master/build/output/knockout-latest.debug.js"></script>
<script src="https://github.com/desandro/isotope/raw/master/jquery.isotope.js"></script>
<div class="root">
    <div id="new-service-container">
        <table>
            <tr>
                <td>Name: </td>
                <td><input type="text" data-bind="value: newName" /></td>
                <td>ID: </td><td><input type="text" data-bind="value: newID"/></td>
            </tr>
            <tr>
                <td>Description: </td>
                <td><input type="text" data-bind="value: newDescription" /></td>
            </tr>
            <tr>
                <td colspan="2"><input type="button" value="Add service" data-bind="click: addService" /></td>
            </tr>
        </table>
        <div id="sort-actions">
            <span>sort by:</span>
            <a data-bind="click: sortByName">Name</a>
            <a data-bind="click: sortByDescription">Description</a>
            <a data-bind="click: sortByID">ID</a>
            <a data-bind="click: sortByDate">Date</a>
            <br />
            <span>sort direction</span>
            <a data-bind="click: sortAsc">Ascending</a>
            <a data-bind="click: sortDesc">Descending</a>
        </div>
    </div>
    <ul id="container" data-bind="template: { name: 'services-template', foreach: services, afterAdd: serviceAdded, beforeRemove: serviceRemoved }, jqIsotope: isotope">
        
    </ul>
</div>

<script type="text/html" id="services-template">
<li class="element" data-bind="click: $parent.removeService">
    <div class="id" data-bind="text: id"></div>
    <div class="name" data-bind="text: name"></div>
    <div class="description" data-bind="text: description"></div>
    <div class="date" data-bind="text: date"></div>
</li>
</script>

CSS

#root { overflow: hidden; }
#container { list-style-type: none; overflow: hidden; }
#container >li { display: block; padding: 12px; margin: 8px; border: 2px outset #eee; border-radius: 4px; float: left; overflow: hidden; cursor: pointer; }
#container >li:hover { background-color: #eee; }
#container >li >div { font-size: 24px; }
a { color: blue; display: inline-block; padding: 2px 4px; cursor: pointer; }
a:hover { text-decoration: underline; }

.isotope-item {
  z-index: 2;
}

.isotope-hidden.isotope-item {
  pointer-events: none;
  z-index: 1;
}

/**** Isotope CSS3 transitions ****/

.isotope,
.isotope .isotope-item {
  -webkit-transition-duration: 0.8s;
     -moz-transition-duration: 0.8s;
      -ms-transition-duration: 0.8s;
       -o-transition-duration: 0.8s;
          transition-duration: 0.8s;
}

.isotope {
  -webkit-transition-property: height, width;
     -moz-transition-property: height, width;
      -ms-transition-property: height, width;
       -o-transition-property: height, width;
          transition-property: height, width;
}

.isotope .isotope-item {
  -webkit-transition-property: -webkit-transform, opacity;
     -moz-transition-property:    -moz-transform, opacity;
      -ms-transition-property:     -ms-transform, opacity;
       -o-transition-property:         top, left, opacity;
          transition-property:         transform, opacity;
}

/**** disabling Isotope CSS3 transitions ****/

.isotope.no-transition,
.isotope.no-transition .isotope-item,
.isotope .isotope-item.no-transition {
  -webkit-transition-duration: 0s;
     -moz-transition-duration: 0s;
      -ms-transition-duration: 0s;
       -o-transition-duration: 0s;
          transition-duration: 0s;
}

JavaScript

ko.bindingHandlers['jqIsotope'] = {
    'update': function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var options = ko.utils.unwrapObservable(valueAccessor());
        if (options) {
            if (Object.prototype.toString.call(options) === '[object Array]') {
                $.fn.isotope.apply($(element), options);
            } else {
                $(element).isotope(options);
            }
        }
    }
};

$(function() {
    function Service(name, description, id, date) {
        var self = this;
        self.name = ko.observable(name);
        self.description = ko.observable(description);
        self.id = ko.observable(id);
        self.date = ko.observable(date);
    }

    function ViewModel() {
        var self = this;
        self.newName = ko.observable();
        self.newDescription = ko.observable();
        self.newID = ko.observable();
        self.services = ko.observableArray([]);
        self.isotope = ko.observable();
        self.addService = function() {
            self.services.push(new Service(self.newName(), self.newDescription(), self.newID()));
        };

        self.removeService = function(service) {
            self.services.remove(service);
        };

        self.sortByName = function() {
            self.isotope({
                sortBy: 'name'
            });
        };
        self.sortByDescription = function() {
            self.isotope({
                sortBy: 'description'
            });
        };
        self.sortByID = function() {
            $('#container').isotope({
                sortBy: 'id'
            });
        };
        self.sortByDate = function() {
            self.isotope({
                sortBy: 'date'
            });
        };
        self.sortAsc = function() {
            self.isotope({
                sortAscending: true
            });
        };
        self.sortDesc = function() {
            self.isotope({
                sortAscending: false
            });
  ...