Events
Events allow you to tap into the life cycle of a query request and perform actions before and after the query is executed. This can be used for adding validation before saving a model, hashing a password or calling some external process after a model is saved.
The way this is done is by attaching event handlers to a model that will listen for these events. If the event handlers return Promises, the handlers will wait for the Promise to be resolved or rejected before progressing. If the promise is rejected, the process will be interrupted.
Listening to events
In order to attach an event listener to a model you can do it in the Model's initialize
method like so:
const User = bookshelf.model('User', {
tableName: 'users',
initialize() {
this.on('updated', (model) => {
// This is fired after a model is updated
})
}
})
You can attach multiple event listeners for the same event by calling the on
method multiple times
and the listeners will run sequentially.
Available save events
The available model
save related events are:
They are fired in this order and it's possible to prevent the request from advancing further by throwing an error or returning a rejected Promise from any one of these event listeners, e.g.:
const User = bookshelf.model('User', {
tableName: 'users',
initialize() {
this.on('saving', (model) => {
if (model.get('status') !== 'active') {
// Throwing an error will prevent the model from being saved
throw new Error('Cannot save inactive user')
}
})
this.on('saved', (model) => {
// This won't be reached if the previous event threw an error
})
}
})
This feature can be used to perform validation before saving a model. For example, checking if an email address already exists and preventing the model from being saved if it does:
const User = bookshelf.model('User', {
tableName: 'users',
initialize() {
this.on('saving', (model) => {
return User.forge({email: model.get('email')})
.fetch({require: false})
.then((user) => {
if (user) throw new Error('That email address already exists')
})
})
}
})
Available fetch related events
The available model
data retrieval related events are:
Available destroy related events
The available model
destruction related events are:
Note that you can get the model's previous attributes after it's destroyed by calling the
previousAttributes
method:
const User = bookshelf.model('User', {
tableName: 'users',
initialize() {
this.on('destroyed', (model) => {
const previousAttributes = JSON.stringify(model.previousAttributes())
log(`Destroyed model with attributes: ${previousAttributes}`)
})
}
})