How can I observe properties on objects without .attr?

I’m working with a 3rd party library that doesn’t use .attr to set properties on its objects. So for example, when I use these objects in a Stache template, and do something like obj.setCount(20); obj.count gets set to 20, but the stache template doesn’t update because .attr wasn’t used.

Yes, I could do obj.attr('count', 20) but in this case, setCount needs to be called so that the other library can update its other attributes. Is there a good way to handle this situation?


in 2.3, you can do:

setCount: function(count){
  var oldValue = this.count;
  this.count = count;
  can.batch.trigger(this, "count", count, oldValue);

You’ll also need to make sure:

  • can.__observe(obj, "count") is called when reading the count value.
  • bind and unbind are on your object (can you do can.simpleExtend(obj, can.event)

In 3.0, it will look like:

var ObserveInfo = require("can-observe-info");
var canBatch = require("can-event/batch/batch");
var canEvent = require("can-event");
var CID = require("can-util/js/cid/cid");
var assign = require("can-util/js/assign/assign");

var Counter = function(initalCount){

assign(Counter.prototype, canEvent);
Counter.prototype.getCount = function(){
  ObserveInfo.observe(this, "count");
  return this.count;
Counter.prototype.setCount: function(count){
  var oldValue = this.count;
  this.count = count;,"count", [count, oldValue]);

Of course, you could just do:

DefineMap = require("can-define/map/map");
Counter = DefineMap.extend({
  count: "number"
c = new Counter({count: 5});

c.count //-> 5
c.count = 10;

Thanks for the quick response! This is helpful to see how 3.0 will handle it also.

In my case, the Counter example would be sort of a “black box” that is generated by a different library. I simplified it for the purpose of the example, but basically I would just need to overwrite the existing setCount with a new one that triggers the event:


library.counter.prototype = can.simpleExtend(library.counter, can.event);

var counter = new library.counter();
var oldCount = counter.setCount;
counter.setCount = function(count){
    var oldValue = this.count;
    this.count = count;
    //update the template
    can.batch.trigger(this, 'count', count, oldValue);
//same thing for getCount using can.__observe

var renderer = can.stache('{{counter.count}}');
can.append(can.$(node), renderer({counter:counter}));