Using an error to capture a subscription call stack in KnockoutJS

by robatwilliams

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-debug.js"></script>
<ol data-bind="foreach: filteredPeople">
    <li data-bind="text: name + ' ' + age"></li>
</ol>

<input type="number" data-bind="value: minAge, valueUpdate: 'afterkeydown'" />

JavaScript

var Person, ViewModel, viewModel;

ko.subscribable.fn._subscribe = ko.subscribable.fn.subscribe;
ko.subscribable.fn.subscribe = function () {
    var subscription = ko.subscribable.fn._subscribe.apply(this, arguments);
    
    try {
        throw new Error();
    } catch (error) {
        subscription.callStack = error.stack;
    }
    
    return subscription;
};

Person = function (name, age) {
    this.name = name;
    this.age = age;
};

ViewModel = function () {
    this.minAge = ko.observable();
    
    this.people = [
        new Person('PersonA', 10),
        new Person('PersonB', 20),
        new Person('PersonC', 30),
        new Person('PersonD', 40),
        new Person('PersonE', 50)
    ];
    
    this.filteredPeople = ko.computed(this._filteredPeople, this);
};
ViewModel.prototype = {
    _filteredPeople: function () {
        var filtered,
            minAge = this.minAge();
        
        if (minAge === null || minAge === undefined) {
            filtered = this.people;
        } else {
            filtered = this.people.filter(function (person) {
                return person.age >= minAge;
            });
        }
        
        return filtered;
    }
};

viewModel = new ViewModel();

ko.applyBindings(viewModel, document.body);