You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
At the moment, LoopBack provides two kinds of hooks:
Model hooks
Model hooks
execute when model methods are called. It is possible to
register only one handler for each hook, handlers are inherited.
It is not possible to register a handler for all methods (wildcard).
Most of these hooks are async, although there are few sync exceptions.
When a hook fails, the execution of a method is aborted.
Model hooks operate at the model level only, they don't have access to any
transport-specific objects like HTTP request. These hooks are executed
every time a model method is invoked.
List of model hooks:
afterInitialize (sync)
beforeValidate
afterValidate
beforeSave
afterSave
beforeCreate
afterCreate
beforeUpdate
afterUpdate
beforeDestroy
afterDestroy
Remote hooks (out of scope)
Remote hooks
execute before or after a remote method is called.
It's possible to register multiple handlers for the same hook. Handlers
are not inherited. One can register a single handler function for all
methods using a wildcard.
Remote hooks operate on the transport level, they have access to
transport-specific objects like HTTP request and response. These hooks
are executed only when the method method is invoked via strong-remoting.
CRUD events (out of scope)
There are also few CRUD events used for change-tracking:
deletedAll (arg: where object)
deleted (arg: model id)
changed (arg: model instance)
set (arg: model instance)
Ideally, these events should be implemented on top of Model hooks.
Model hooks in action
Item.create({ name: 'first' }, cb)
afterInitialize
this: model { name: 'first' }
beforeValidate
this: model { name: 'first' }
arg1: data { name: 'first', id: undefined }
afterValidate
this: model { name: 'first' }
arg1: data undefined
beforeCreate
this: model { name: 'first' }
arg1: model { name: 'first' }
beforeSave
this: model { name: 'first' }
arg1: model { name: 'first' }
afterSave
this: model { name: 'first', id: 1 }
arg1: data undefined
afterCreate
this: model { name: 'first', id: 1 }
arg1: data undefined
Item.find(cb)
afterInitialize
this: model { name: 'first', id: 1 }
afterInitialize
this: model { name: 'second', id: 2 }
item.save(sb)
beforeValidate
this: model { name: 'first-updated', id: 1 }
arg1: data undefined
afterValidate
this: model { name: 'first-updated', id: 1 }
arg1: data undefined
beforeSave
this: model { name: 'first-updated', id: 1 }
arg1: data { name: 'first-updated', id: 1 }
beforeUpdate
this: model { name: 'first-updated', id: 1 }
arg1: data { name: 'first-updated', id: 1 }
afterInitialize
this: model { name: 'first-updated', id: 1 }
afterUpdate
this: model { name: 'first-updated', id: 1 }
arg1: data undefined
afterSave
this: model { name: 'first-updated', id: 1 }
arg1: data undefined
The text below is an initial draft that is no longer accurate.
The pull request loopbackio/loopback-datasource-juggler#403 introduces a new API for "intent-based" hooks. These hooks are not tied to a particular method (e.g. "find" or "update"). Instead, they are triggered from all methods that execute a particular "intent".
The consumer API is simple, there is a new method Model.observe(name, observer), where the observer is function observer(context, callback).
The contex object is specific to hooks and it does not have any relation
to the context object passed to remoting hooks registered via Model.beforeRemote
and Model.afterRemote. The context object is not related to the "current context"
provided by loopback.getCurrentContext() either.
Observers are inherited by child models and it is possible to register multiple observers for the same hook.
access
The access hook is triggered whenever a database is queried for models. Observers
may modify the query, e.g. by adding extra restrictions.
Context properties
Model - the constructor of the model that will be queried
query - the query containing fields where, include, order, etc.
The hook before save is triggered before a model instance is about to be modified (created, updated). The hook is triggered before the validation.
Depending on which method triggered this hook, the context will have one of the following sets of properties.
Full save of a single model
Model - the constructor of the model that will be saved
instance - the model instance to be saved. The value is an instance of Model class.
Partial update of possibly multiple models
Model - the constructor of the model that will be saved
where - the where filter describing which instances will be affected
data - the (partial) data to apply during the update
Examples:
MyModel.observe('before save',functionupdateTimestamp(ctx,next){if(ctx.instance){ctx.instance.updated=newDate();}else{ctx.data.updated=newDate();}next();});MyModel.observe('before save',functioncomputePercentage(ctx,next){if(ctx.instance){ctx.instance.percentage=100*ctx.instance.part/ctx.instance.total;}elseif(ctx.data.part&&ctx.data.total){ctx.data.percentage=100*ctx.data.part/ctx.data.total;}elseif(ctx.data.part||ctx.data.total){// either report an error or fetch the missing properties from DB}next();});
after save
The hook after save is called after a model change was successfully persisted
to the datasource.
Depending on which method triggered this hook, the context will have one of the following
sets of properties.
Single model
Model - the constructor of the model that will be saved
instance - the model instance that was saved. The value is an instance of Model class
and contains updated values computed by datastore (e.g. auto-generated id).
Partial update of possibly multiple models
Model - the constructor of the model that will be saved
where - the where filter describing which instances were queried
data - the (partial) data applied during the update
At the moment, this second set is used exclusively by Model.updateAll.
The following table shows which new hook
to use for each of the existing (old) hooks:
Old hook name
New hook to use
beforeValidate
before save
beforeCreate
before save
afterCreate
after save
beforeSave
before save
afterSave
after save
beforeUpdate
before save
afterUpdate
after save
beforeDestroy
before delete
afterDestroy
after delete
The following hook doesn't have any counterpart:
afterValidate. If you have a specific
use case that cannot be implemented without it,
then please open a github issue and describe your requirements
there. We will consider adding a replacement for this hook.
List of hooks invoked by PersistedModel methods
Method name
Hooks invoked
all
access
find
access
findOne
access
findById
access
findByIds
access
create
before save, after save
updateOrCreate
access, before save, after save
findOrCreate
access, before save (1), after save (1)
exists
access
count
access
deleteAll
access, before delete, after delete
deleteById
access, after delete
updateAll
access, before save, after save
prototype.save
before save, after save
prototype.delete
before delete, after delete
prototype.updateAttributes
before save, after save
(1) When findOrCreate finds an existing model, the save hooks
are not triggered. However, connectors providing atomic implementation
may trigger before save hook even when the model won't created,
as they cannot determine in advance whether the model will be created
or not.
Is there a way to update other models inside a hook? For example:
Model1.afterUpdate=function(next){varapp=Model1.app;varModel2=app.models.Model2;Model2.someFunction(next);// I get "Error: Can't set headers after they are sent."next();};
Is there a way to update other models inside a hook? For example:
What's the recommended approach here?