Contrary to solutions given in comments to your question, I suggest that you do not mix DOM-handling and ViewModel functionality in the viewmodel methods. Generally, I suggest avoiding doing anything which makes the viewmodel depending on the DOM.
When it comes to animations for the foreach-binding I would first recommend creating a custom bindingHandler which would actually use the foreach-binding and add the animations you want. This way, you can keep the DOM-related code in the view or the bindingHandlers, where they are supposed to be.
In some scenarios you might not want to create a custom binding for it, but just want the animation methods available to your foreach binding. In these cases, putting these methods on a viewmodel could be a more pragmatic approach. However, if you do this, I would recommend avoiding having your viewmodel functionality depending on these methods at all, just keep them only for doing the DOM animation logic.
Given such an approach, your viewmodel could then look similar to (copying the one in your fiddle and then adding the animation methods):
function ViewModel() {
var self = this;
self.selectedCategory = ko.observable("");
self.setCategory = function (newCat) {
self.selectedCategory(newCat);
};
self.allCharities = ko.observableArray([
new Charity(0, "Amnesty International", "$2,466", "HUMANITARIAN"),
new Charity(1, "Richard Dawkins Foundation", "$0", "EDUCATION"),
new Charity(2, "Khaaaan Academy", "13,859", "EDUCATION"),
new Charity(4, "Wikipedia", "$7,239", "EDUCATION")
]);
self.filteredCharities = ko.computed(function () {
// If no category is selected, return all charities
if (!self.selectedCategory())
return self.allCharities();
// Return charities in the selected category
return ko.utils.arrayFilter(self.allCharities(), function (c) {
return (c.Category() == self.selectedCategory());
});
}, this);
var fadeAnimationDuration = 500;
self.animationAfterAddingCharityElementsToDom = function(element){
//Since this method will be depending on the DOM, avoid having
//the viewmodel functionality depending on this method
//First hide the new element
var $categoryDomElement = $(element);
$categoryDomElement.hide();
var $tabDomElement = $categoryDomElement.parent();
$tabDomElement.fadeOut(fadeAnimationDuration, function(){
//When the tab has faded out, show the new element and then fade the tab back in
$categoryDomElement.show();
$tabDomElement.fadeIn(fadeAnimationDuration);
});
};
self.animationBeforeRemovingCharityElementsFromDom = function(element){
//Since this method will be depending on the DOM, avoid having
//the viewmodel functionality depending on this method
var $categoryDomElement = $(element);
var $tabDomElement = $categoryDomElement.parent();
$tabDomElement.fadeOut(fadeAnimationDuration, function(){
//When the tab has faded out, remove the element and then fade the tab back in
$categoryDomElement.remove();
$tabDomElement.fadeIn(fadeAnimationDuration);
});
};
};
And your binding would then be:
<div class="tab" data-bind="foreach: { data: filteredCharities, afterAdd: animationAfterAddingCharityElementsToDom, beforeRemove: animationBeforeRemovingCharityElementsFromDom }">
<div class="tab-tile mb21" data-bind="css:{'mr21':$index()%3 < 2}">
<a href="#" class="amount" data-bind="text: Amount"></a>
<a href="#" class="title" data-bind="text: Name"></a>
<a href="#" class="category" data-bind="text: Category"></a>
</div>
</div>
I have updated your fiddle with the above code and you can find it at http://jsfiddle.net/LkqTU/23825/.
It could also be a good idea (and more "correct") to add these methods to the viewmodel constructor prototype instead, if you expect that you're going to create more than one instance.