docs/tutorial-events.html
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.
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.
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')
})
})
}
})
The available model data retrieval related events are:
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}`)
})
}
})