Skip to content

Bookshelf Virtuals Plugin

Ricardo Graça edited this page Aug 9, 2019 · 2 revisions

Introduction

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, for example. The virtuals plugin helps you easily achieve this type of behavior.

How to use

First install the package:

npm install bookshelf-virtuals-plugin

Then load the plugin using bookshelf.plugin('bookshelf-virtuals-plugin'). Now you are all set to define virtuals on your models.

Defining virtuals

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:

const ModelWithVirtuals = bookshelf.Model.extend({
  virtuals: {
    fullName() {
        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:

const 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:

const ModelWithVirtuals = bookshelf.Model.extend({
  virtuals: {
    fullName: {
      get() {
        return this.get('firstName') + ' ' + this.get('lastName')
      },
      set(value) {
        value = value.split(' ')
        this.set('firstName', value[0])
        this.set('lastName', value[1])
      }
    }
  }
})

If a setter is not defined, set calls will do nothing. When defining a virtual with a get and a set property, it can be used in the following way:

const 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.

Converting model to JSON

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 off their inclusion 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:

const ModelWithVirtuals = bookshelf.Model.extend({
  outputVirtuals: false
  virtuals: {
    fullNamen() {
        return this.get('firstName') + ' ' + this.get('lastName')
    }
  }
})

const instance = new ModelWithVirtuals({firstName: 'Joe', lastName: 'Shmoe'})

instance.toJSON() // => {"firstName: "Joe", "lastName": "Shmoe"}
instance.toJSON({virtuals: true}) // => {"firstName: "Joe", "lastName": "Shmoe", "fullName": "Joe Shmoe"}
Clone this wiki locally