How can I construct a can.Map with computed values that behave like normal attributes?

74 Views Asked by At

Let's say I have a map:

map = new can.Map({foo: 'bar'})

and I want to bind the value of foo in another map. I could do:

otherMap = new can.Map({fizzle: map.compute('foo')})

but this doesn't behave the way I would expect.

  1. I would expect otherMap.attr('fizzle') to return bar, but instead it returns a function. I have to call otherMap.attr('fizzle')() instead.
  2. I would expect to be able to change the value by calling otherMap.attr('fizzle', 'moo'), but this doesn't change the computed value. Instead, if I want to change the underlying value, I have to call otherMap.attr('fizzle')('moo').

Is there a way to create a map with computed values that behave like normal attributes?

Thanks!

1

There are 1 best solutions below

0
On

I would recommend using the define plugin which makes it easy to create computed getters and setters without having to explicitly create computes. In your example like this:

var map = new can.Map({
    foo: 'bar',
    baz: 'bla'
});

var OtherMap = can.Map.extend({
    define: {
        fizzle: {
            get: function() {
                return map.attr('foo') + '/' + map.attr('baz');
            },
            set: function(value) {
                map.attr('foo', value);
            }
        }
    } });

var other = new OtherMap();

console.log(other.attr('fizzle'));

other.attr('fizzle', 'something');
console.log(map.attr('foo'));

Demo in this Fiddle.