COMPUTE-ATTR

  • property

{can.compute(getterSetter, context)}

 

Deprecated 2.3

Using attributes as a compute directly have been deprecated in favor of the define plugin, which provides the same functionality. It will still be maintained up to 3.0 and potentially after. Projects using computes as a direct attribute should consider switching the define plugin.

Specify an attribute that is computed from other attributes.

can.compute(getterSetter, context)

A compute that reads values on instances of the map and returns a derived value. The compute may also be a getter-setter compute and able to be passed a value.

Use

When extending can.Map, if a prototype property is a can.compute it will setup that compute to behave like a normal attribute. This means that it can be read and written to with attr and bound to with bind.

The following example makes a fullName attribute on Person maps:

var Person = can.Map.extend({
    fullName: can.compute(function(){
        return this.attr("first") + " " + this.attr("last")
    })
})

var me = new Person({first: "Justin", last: "Meyer"})

me.attr("fullName") //-> "Justin Meyer"

me.bind("fullName", function(ev, newValue, oldValue){
    newValue //-> Brian Moschel
    oldValue //-> Justin Meyer
})

me.attr({first: "Brian", last: "Moschel"})

Getter / Setter computes

A compute's setter will be called if attr is used to set the compute-property's value.

The following makes fullName able to set first and last:

var Person = can.Map.extend({
    fullName: can.compute(function(newValue){
        if( arguments.length ) {
            var parts = newValue.split(" ");
            this.attr({
                first: parts[0],
                last:  parts[1]
            });
        } else {
            return this.attr("first") + " " + this.attr("last");
        }
    })
})

var me = new Person({first: "Justin", last: "Meyer"})

me.attr("fullName", "Brian Moschel")
me.attr("first") //-> "Brian"
me.attr("last")  //-> "Moschel"

Alternatives

can.mustache and can.ejs will automatically convert any function read in the template to a can.compute. So, simply having a fullName function like:

var Person = can.Map.extend({
    fullName: function(){
        return this.attr("first") + " " + this.attr("last")
    }
})
var me = new Person({first: "Justin", last: "Meyer"})

Will already be live-bound if read in a template like:

{{me.fullName}}
// or
<%= me.attr("fullName") %>

The setter plugin can also provide similar functionality as Getter/Setter computes.