addConverter
Register a helper for bidirectional value conversion.
stache.addConverter(converterName, getterSetter)
Creates a helper that can do two-way conversion between two values. This is especially useful with two-way bindings like:
<input value:bind='stringToNumber(age)'/>
A converter helper provides:
- a
get
method that returns the value of theleft
value given the arguments passed on theright
. - a
set
method that updates one or multiple of theright
arguments computes given a newleft
value.
stringToNumber
might convert a number (age
)
to a string (value
), and the string (value
) to a number (age
)
as follows:
import {stache, Reflect as canReflect, DefineMap} from "can";
stache.registerConverter( "stringToNumber", {
get: function( numberObservable ) {
return "" + canReflect.getValue(numberObservable);
},
set: function( string, numberObservable ) {
canReflect.setValue(numberObservable, +string);
}
} );
var data = new DefineMap({age: 36});
var frag = stache(`<input value:bind="age"/> Age: {{age}}`)(data);
document.body.append(frag);
Parameters
- converterName
{String|Object}
:The name of the converter helper or an object to register multiple converters at once.
- getterSetter
{getterSetter}
:An object containing get() and set() functions.
Use
NOTE: Before creating your own converter, you may want to look at what’s provided by can-stache-converters.
These helpers are useful for avoiding creating can-define/map/map getters and setters that do similar conversions on the view model. Instead, a converter can keep your viewModels more ignorant of the demands of the view. Especially as the view’s most common demand is that everything must be converted to a string.
That being said, the following is a richer example of a converter, but one that should probably be part of a view model.
<input value:bind='hoursAndMinutes(hours, minutes)'/>
The following converts both ways hours
and minutes
to value
.
import {stache, DefineMap, queues, Reflect as canReflect} from "can";
stache.addConverter( "hoursAndMinutes", {
get: function( hours, minutes ) {
return ""+canReflect.getValue( hours ) +":"+ canReflect.getValue( minutes );
},
set: function( newFullName, hours, minutes ) {
queues.batch.start();
const parts = newFullName.split( ":" );
canReflect.setValue( hours , +parts[0] );
canReflect.setValue( minutes , +parts[1] );
queues.batch.stop();
}
} );
var data = new DefineMap({hours: 3, minutes: 17});
var frag = stache(`
<input value:bind="hoursAndMinutes(hours, minutes)"/>
Hours: {{hours}}, Minutes: {{minutes}}`
)(data);
document.body.append(frag);
It is possible to add multiple converters at once by passing an object instead of a string to the name
argument:
import {stache, DefineMap, queues, Reflect as canReflect} from "can";
stache.addConverter({
"numberToHex": {
get: function(val) {
return canReflect.getValue(val).toString(16);
},
set: function(val, valCompute) {
return canReflect.setValue(valCompute, parseInt("0x" + val));
}
},
"capitalize": {
get: function(val){
return canReflect.getValue(val).toString().toUpperCase();
},
set: function(val, valCompute) {
return canReflect.setValue(valCompute, val.toLowerCase());
}
}
});
var data = new DefineMap({fname: "Cherif", age: 36});
var frag = stache(`
<div>
<input value:bind="capitalize(fname)"/>
Firstname: {{fname}}
</div>
<div>
<input value:bind="numberToHex(age)"/>
Age: {{age}}
</div>
`
)(data);
document.body.append(frag);