-
Notifications
You must be signed in to change notification settings - Fork 575
Plugin: Virtuals
Sometimes you might want to compute additional values on your model based on other values. Maybe you want to generate a fullName
property, based on a firstName
and lastName
? The virtuals plugin helps you to easily achieve this type of behavior.
First load the plugin using Bookshelf.plugin('virtuals')
. Now you are all set to define virtuals
on your models.
Defining virtuals is very easy. Let's stick with the example of generating a fullName
property from a firstName
and lastName
property. At first we define a model, which has a special property virtuals
:
var ModelWithVirtuals = bookshelf.Model.extend({
virtuals: {
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}
}
});
The above code will will generate a virtual property on your extended model, which can be accessed in two ways:
var instance = new ModelWithVirtuals({firstName: 'Joe', lastName: 'Shmoe'});
instance.fullName // => 'Joe Shmoe'
instance.get('fullName') // => 'Joe Shmoe'
This virtual property is a simple getter. If you want to also use it to set properties, you can define it like this:
var ModelWithVirtuals = bookshelf.Model.extend({
virtuals: {
fullName: {
get: function () {
return this.get('firstName') + ' ' + this.get('lastName');
},
set: function(value) {
value = value.split(' ');
this.set('firstName', value[0]);
this.set('lastName', value[1]);
}
}
}
});
If a setter is not defined, set
calls will be noops. When defining a virtual with a get
and a set
property, it can be used in the following way:
var instance = new ModelWithVirtuals({firstName: 'Joe', lastName: 'Shmoe'});
instance.fullName // => 'Joe Shmoe'
// now we set a new value
instance.fullName = 'Jack Shmoe';
instance.fullName // => 'Jack Shmoe'
instance.get('firstName') // => 'Jack'
instance.get('lastName') // => 'Shmoe'
instance.set('fullName', 'John Doe');
instance.fullName // => 'John Doe'
instance.get('firstName') // => 'John'
instance.get('lastName') // => 'Doe'
This can be a very powerful feature, if used correctly.
By default all virtual properties are included when you convert your model to json. If you do not want them to be included you can turn inclusion off, by passing outputVirtuals: false
when extending the model. This will override the default behavior.
But you do not have to always change the default behavior, if you want to include or exclude them on a per case basis, then that's fine too! You can pass an options hash to the toJSON
method of the model, which will always override the default behavior:
var ModelWithVirtuals = bookshelf.Model.extend({
outputVirtuals: false
virtuals: {
fullName: function() {
return this.get('firstName') + ' ' + this.get('lastName');
}
}
});
var instance = new ModelWithVirtuals({firstName: 'Joe', lastName: 'Shmoe'});
instance.toJSON() // => {"firstName: "Joe", "lastName": "Shmoe"}
instance.toJSON({virtuals: true}) // => {"firstName: "Joe", "lastName": "Shmoe", "fullName": "Joe Shmoe"}