Meteoric Spreadsheet Example

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<script src="https://s3.amazonaws.com/www.chicagogrooves.com/js/meteor-reactive-packages.js"></script>
<h1>Reactive Worksheet Example</h1>

<p>
    To see working with a UI bound to this, try: <a href="http://app-xz8xq6d5.meteorpad.com/">this sample on Meteorpad.com</a>
</p>

<p>
Or to play here, open a console and investigate the following:
</p>

<pre>
//investigate current state of the object
[wks.a1, wks.a2, wks.subtotal]

//change one field
wks.a1 += 2.2

//and others follow suit!
[wks.a1, wks.a2, wks.subtotal]

//updates happen in the next turn of the event loop
curTotal = wks.total; wks.a1 += 1; curTotal === wks.total //still equal!

//so call flush to force an update (no longer equal, whew!)
curTotal = wks.total; wks.a1 += 1; Tracker.flush(); curTotal === wks.total

//Because of this deferred-by-default update, multiple updates still result in only one recompute.
(function(){ wks.a1 += 1.1; wks.a2 += 0.2; })()


</pre>

CSS

/* CSS declarations go here */
table, td{
    border: 1px solid #aaa;
    padding: 3px;
    border-spacing: 3px;
    border-collapse: collapse;
}
td{ width: 75px;}

JavaScript

var wks = worksheet({
    taxRate: 1.08,
    a1: 3,
    a2: 20,
    subtotal: function () {return this.a1 + this.a2;},
    total: function () {
        console.log('updating total');
        return this.taxRate * this.subtotal;
    }
});

//to play around with in console
window.wks = wks;


/* begin content from deanius:worksheet package */
function defineReactiveProperty(o, name, ival) {
    var myvar = new ReactiveVar(ival);
    return Object.defineProperty(o, name, {
        get: function() {
            return myvar.get();
        },
        set: function(x) {
            return myvar.set(x);
        }
    });
};

function defineComputedProperty (o, name, fn) {
    var myvar = new ReactiveVar;
    Tracker.autorun(function() {
        var result = fn.call(o); //'this' will be 'o'
        myvar.set(result);
    });
    return Object.defineProperty(o, name, {
        get: function() {
            return myvar.get();
        }
    });
};

function worksheet (spec) {
    var wks = {};
    _.each(spec, function(val, name){
        if(_.isFunction(val)){
            defineComputedProperty(wks, name, val);
        } else {
            defineReactiveProperty(wks, name, val);
        }
    });
    return wks;
}

/* end content from deanius:worksheet package */