Combine Knockout and Isotope (mbest version)
Make Isotope layout elements as they are added to or removed from a ko.observableArray.
HTML
<script src="http://knockoutjs.com/downloads/knockout-3.0.0.js"></script>
<script src="http://isotope.metafizzy.co/jquery.isotope.min.js"></script>
<script src="http://mbest.github.io/knockout-deferred-updates/knockout-deferred-updates.js"></script>
<script src="https://rawgithub.com/mbest/7577891/raw/5fd0f93cc7b018346482d7496f932891b44905f4/mbest-knockout-isotope.js"></script>
<h1>Knockout Isotope Binding Demo</h1>
<p>This is a demonstration of Michael Best's <a href="https://gist.github.com/mbest/7577891">Knockout-Isotope</a> binding for <a href="http://knockoutjs.com/">Knockout</a>, which visualizes Knockout observableArrays through <a href="http://isotope.metafizzy.co/index.html">Isotope</a>.
</p>
<p>Click on an item to remove it or click in the item container to add a new item</p>
<button data-bind="click: addSome" type="button">Add some</button>
<button data-bind="click: removeSome" type="button">Remove some</button>
<button data-bind="click: addRemoveSome" type="button">Add/remove some</button>
<button data-bind="click: shuffle" type="button">Shuffle</button>
<div id="container" data-bind="isotope: { data: items, isotopeOptions: getOptions }, click: addItem">
<div data-bind="text: text, click: $parent.removeItem, clickBubble: false"></div>
</div>
CSS
body {
margin:20px 20px;
}
h1 {
font-size: 24px;
font-weight: bold;
margin-bottom: 12px;
}
#container {
margin-top: 20px;
border: 1px dashed;
border-radius: 4px;
}
p + p {
margin-top: 10px;
}
.isotope-item {
border-radius: 4px;
background-color: blue;
border: none;
width: 200px;
height: 150px;
text-align: center;
line-height: 150px;
margin-bottom: 10px;
}
/**** Isotope Filtering ****/
.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: -o-transform, 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
function shuffle(o){ //v1.0
for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
}
function ItemModel(parent) {
var value, self = this,
found, i;
for (value = 0; value < parent.items().length; ++value) {
found = false;
for (i in parent.items()) {
var item = parent.items()[i];
if (item.value() == value) {
found = true;
break;
}
}
if (!found) {
break;
}
}
this.value = ko.observable(value);
this.text = ko.computed(function () {
return "Item " + self.value();
});
}
var ViewModel = function () {
var self = this;
self.items = ko.observableArray();
this.removeItem = function (item) {
self.items.remove(item);
};
this.addItem = function () {
var item = new ItemModel(self);
self.items.splice(item.value(), 0, item);
};
this.removeRandom = function () {
if (self.items().length) {
self.items.splice(Math.floor(Math.random()*self.items().length), 1);
}
};
this.addSome = function () {
self.addItem();
self.addItem();
self.addItem();
};
this.removeSome = function () {
self.removeRandom();
self.removeRandom();
self.removeRandom();
};
this.addRemoveSome = function () {
self.addSome();
self.removeSome();
};
this.shuffle = function () {
shuffle(self.items());
self.items.valueHasMutated();
};
// Knockout callback for getting Isotope options
this.getOptions = function () {
return {
masonry: {
columnWidth: 210
}
};
};
for (var i=0; i<9; i++)
this.addItem();
};
ko.applyBindings(new ViewModel("Test"));