can-define
Add observable properties, type conversion, and getter/setter logic to your constructor prototypes.
API
can-define function
Exports the can.define
method that defines observable properties and their behavior.
can.define(prototype, propDefinitions)
Define observable properties, type conversion, and getter/setter logic to your constructor prototypes.
var Person = function(first, last){
this.first = first;
this.last = last;
};
can.define(Person.prototype,{
first: {
type: "string"
},
last: {
type: "string"
},
fullName: {
get: function(){
return this.first+" "+this.last;
}
}
});
-
prototype {Object}
:
The prototype object of a constructor function.
-
propDefinitions {Object<String,propDefinition>}
:
An object of
properties and their definitions.
propDefinition {Object}
Defines the type, initial value, and get, set, and serialize behavior for an
observable property.
Object
-
value {function|*}
:
Specifies the initial value of the property or
a function that returns the initial value.
var Person = DefineMap.extend({
age: {value: 0}
});
new Person().age
Object
types should not be specified directly on value
because that same object will
be shared on every instance of the Map. Instead, a function that returns a fresh copy should be provided:
var Person = DefineMap.extend({
address: {
value: function(){
return {city: "Chicago", state: "IL"};
};
}
});
new Person().address
-
Value {function}
:
Specifies a function that will be called with new
whose result is
set as the initial value of the attribute.
var Person = DefineMap.extend({
hobbies: {Value: DefineList}
});
new Person().hobbies
-
type {function|String}
:
Specifies the type of the
property. The type can be specified as either a function
that returns the type coerced value or one of the types names.
var Person = DefineMap.extend({
age: {type: "number"},
hobbies: {
type: function(newValue){
if(typeof newValue === "string") {
return newValue.split(",")
} else if( Array.isArray(newValue) ) {
return newValue;
}
}
}
});
var me = new Person({age: "33", hobbies: "bball,js"})
me.age
me.hobbies
-
Type {function}
:
A constructor function that takes
the value passed to [can.Map::attr attr] as the first argument and called with
new. For example, if you want whatever
gets passed to go through new Array(newValue)
you can do that like:
define: {
items: {
Type: Array
}
}
If the value passed to [can.Map::attr attr] is already an Array, it will be left as is.
-
set {can.Map.prototype.define.set}
:
A set function that specifies what should happen when an attribute
is set on a [can.Map]. set
is called with the result of type
or Type
. The following
defines a page
setter that updates the map's offset:
define: {
page: {
set: function(newVal){
this.attr('offset', (parseInt(newVal) - 1) *
this.attr('limit'));
}
}
}
-
get {get(lastSetValue)}
:
A function that specifies how the value is retrieved. The get function is
converted to an [can.compute.async async compute]. It should derive its value from other values
on the map. The following
defines a page
getter that reads from a map's offset and limit:
define: {
page: {
get: function (newVal) {
return Math.floor(this.attr('offset') /
this.attr('limit')) + 1;
}
}
}
A get
definition makes the property computed which means it will not be serialized by default.
-
serialize {can.Map.prototype.define.serialize|Boolean}
:
Specifies the behavior of the
property when [can.Map::serialize serialize] is called.
By default, serialize does not include computed values. Properties with a get
definition
are computed and therefore are not added to the result. Non-computed properties values are
serialized if possible and added to the result.
Paginate = can.Map.extend({
define: {
pageNum: {
get: function(){ return this.offset() / 20 }
}
}
});
p = new Paginate({offset: 40});
p.serialize()
If true
is specified, computed properties will be serialized and added to the result.
Paginate = can.Map.extend({
define: {
pageNum: {
get: function(){ return this.offset() / 20 },
serialize: true
}
}
});
p = new Paginate({offset: 40});
p.serialize()
If false
is specified, non-computed properties will not be added to the result.
Paginate = can.Map.extend({
define: {
offset: {
serialize: false
}
}
});
p = new Paginate({offset: 40});
p.serialize()
If a [can.Map.prototype.define.serialize serialize function] is specified, the result
of the function is added to the result.
Paginate = can.Map.extend({
define: {
offset: {
serialize: function(offset){
return (offset / 20)+1
}
}
}
});
p = new Paginate({offset: 40});
p.serialize()
types {Object}
Defines the type, initial value, and get, set, and serialize behavior for an
observable property. All type converters leave null
and undefined
as is except for
the "boolean"
type converter.
Object
- observable
{function}
:
The default type behavior. It converts plain Objects to
DefineMaps and plain Arrays to DefineLists. Everything else is left as is. - any
{function}
:
Leaves the set value as is, performs no type conversion. Aliased as *
. - string
{function}
:
Converts to a string with ""+val
. - date
{function}
:
Converts to a JavaScript date using Date.parse(val)
if a string is given or new Date(val)
if a number is passed. - number
{function}
:
Converts to a number with +(val)
. - boolean
{function}
:
Converts to false
if val
is falsey, "0"
, or "false"
; otherwise, converts to true
. - htmlbool
{function}
:
Like boolean
, but converts to true
if empty string (""
) is passed. - compute
{function}
:
Allows computes to be passed and the property take on the value of the compute. - stringOrObservable
{function}
:
Converts plain Objects to DefineMaps, plain Arrays to DefineLists and everything else to strings. This is useful for routing.
can-define/map/map function
Create observable objects.
new can.DefineMap([props])
Creates a new instance of DefineMap or an extended DefineMap.
var person = new can.DefineMap({
first: "Justin",
last: "Meyer"
})
- props
{Object}
:
Properties and values to seed the map with.
- returns
{can-define/map/map}
:
An instance of can.DefineMap
with the properties from props.
can.DefineMap.extend([name,] [static,] prototype)
Extends can.DefineMap, or constructor functions derived from can.DefineMap,
to create a new constructor function.
var Person = can.DefineMap.extend(
"Person",
{seal: true},
{
first: "string",
last: {type: "string"},
fullName: {
get: function(){
return this.first+" "+this.last;
}
},
age: {value: 0},
});
var me = new Person({first: "Justin", last: "Meyer"})
me.fullName
me.age
-
name {String}
:
Provides an optional name for this type that will
show up nicely in debuggers.
-
static {Object}
:
Static properties that are set directly on the
constructor function.
-
prototype {Object<String,function|String|types|propDefinition>}
:
A definition of the properties or methods on this type.
If the property definition is a plain function, it's considered a method.
var Person = DefineMap.extend({
sayHi: function(){ console.log("hi"); }
});
var me = new Person();
me.sayHi();
If the property definition is a string, it's considered a type
setting to be looked up in can.define.types.
var Person = DefineMap.extend({
age: 'number',
isCool: 'boolean',
hobbies: 'observable'
});
var me = new Person({age: '33', isCool: 'false', hobbies: ['js','bball']});
me.age
me.isCool
me.hobbies instanceof DefineList
If the property definition is a Constructor function, it's considered a Type
setting.
var Address = DefineMap.extend({
zip: 'number'
});
var Person = DefineMap.extend({
address: Address
});
var me = new Person({address: {zip: '60048'}});
me.address.zip
If the property is an object, it's considered to be a propDefinition.
var Person = DefineMap.extend({
fullName: {
get: function() {
return this.first+" "+this.last;
},
set: function(newVal) {
var parts = newVal.split(" ");
this.first = parts[0];
this.last = parts[1];
}
},
address: {
Type: {
zip: "number"
}
}
});
var me = new Person({fullName: "Rami Myer", address: {zip: '60048'}});
me.first
me.address.zip
seal {Boolean}
Defines if instances of the map should be sealed in development.
Boolean
If true
, in development, instances of this object will be sealed. In strict mode errors will be thrown when undefined properties are set. This is the default
behavior of extended DefineMaps:
"use strict";
var Person = can.DefineMap.extend({});
var me = new Person();
me.age = 33
If false
, the object will not be sealed. This is the default behavior of
unextended DefineMaps. Use get and set to get and set values:
var person = new can.DefineMap();
person.set("first","Justin");
person.set("last","Meyer");
person.get("first")
person.get("last")
Set seal
to false
on objects that have an indeterminate number of properties:
var Style = can.DefineMap.extend({
seal: false
},{
cssText: {
get: function(){
return _.map(this.get(), function(val, prop){
return prop+": "+val;
}).join(";")
}
}
});
var style = new Style();
style.set("color","green");
style.set("font","awesome");
style.cssText
map.each( callback(item, propName ) )
each
iterates through the Map, calling a function
for each property value and key.
- callback
{function(item, propName)}
:
the function to call for each property
The value and key of each property will be passed as the first and second
arguments, respectively, to the callback. If the callback returns false,
the loop will stop.
- returns
{can.Map}
:
this Map, for chaining
map.toObject()
map.serialize()
map.get(propName)
map.set(propName, value)
can-define/list/list function
Create observable list.
new can.DefineList([items])
map.item(index, [newVal])
map.items()
list.each( callback(item, index) )
each
iterates through the Map, calling a function
for each element.
- callback
{function(*, Number)}
:
the function to call for each element
The value and index of each element will be passed as the first and second
arguments, respectively, to the callback. If the callback returns false,
the loop will stop.
- returns
{can.DefineList}
:
this DefineList, for chaining
list.forEach(callback[, thisArg])
- callback
{function(element, index, list)}
:
a function to call with each element of the DefineList
The three parameters that callback gets passed are element, the element at index, index the
current element of the list, and list the DefineList the elements are coming from. - thisArg
{Object}
:
the object to use as this
inside the callback
list.splice(index[, howMany[, ...newElements]])
-
index {Number}
:
where to start removing or inserting elements
-
howMany {Number}
:
the number of elements to remove
If howMany is not provided, splice
will remove all elements from index
to the end of the DefineList.
-
newElements {*}
:
elements to insert into the DefineList
- returns
{Array}
:
the elements removed by splice
list.replace(collection)
- collection
{Array|can.DefineList|can.Deferred}
:
the collection of new elements to use
If a [can.Deferred] is passed, it must resolve to an Array
or can.DefineList
.
The elements of the list are not actually removed until the Deferred resolves.
list.push(...elements)
push
adds elements onto the end of a DefineList.
- elements
{*}
:
the elements to add to the DefineList
- returns
{Number}
:
the new length of the DefineList
list.unshift(...elements)
unshift
adds elements onto the beginning of a DefineList.
- elements
{*}
:
the elements to add to the DefineList
- returns
{Number}
:
the new length of the DefineList
list.pop()
pop
removes an element from the end of a DefineList.
- returns
{*}
:
the element just popped off the DefineList, or undefined
if the DefineList was empty
list.shift()
shift
removes an element from the beginning of a DefineList.
- returns
{*}
:
the element just shifted off the DefineList, or undefined
if the DefineList is empty
list.indexOf(item)
indexOf
finds the position of a given item in the DefineList.
- item
{*}
:
the item to find
- returns
{Number}
:
the position of the item in the DefineList, or -1 if the item is not found.
list.join(separator)
join
turns a DefineList into a string by inserting separator between the string representations
of all the elements of the DefineList.
- separator
{String}
:
the string to seperate elements with
- returns
{String}
:
the joined string
list.reverse()
reverse
reverses the elements of the DefineList in place.
- returns
{can.DefineList}
:
the DefineList, for chaining
list.slice([start[, end]])
slice
creates a copy of a portion of the DefineList.
-
start {Number}
:
the index to start copying from
-
end {Number}
:
the first index not to include in the copy
If end is not supplied, slice
will copy until the end of the list.
- returns
{can.DefineList}
:
a new can.DefineList
with the extracted elements
list.concat(...args)
- args
{Array|can.DefineList|*}
:
Any number of arrays, Lists, or values to add in
For each parameter given, if it is an Array or a DefineList, each of its elements will be added to
the end of the concatenated DefineList. Otherwise, the parameter itself will be added.