Skip to main content

Hooks

Hooks are used to:

  • modify the data before it is saved to the database on create or update
  • execute something after data were saved or deleted
  • change the query before fetching items from the database
  • modify the fetched data before it is displayed in the list and show
  • prevent the request to db depending on some condition (Better use allowedActions for this)

Modify the data before it is saved to the database

Let's add reference to adminUser when user creates a new apartment:

./resources/apartments.ts
import type { AdminUser } from  'adminforth';

{
...
resourceId: 'aparts',
columns: [
...
{
name: 'realtor_id',
...
showIn: ['list', 'show', 'edit'], // don't even show this field in create
...
},
...
],
...
hooks: {
create: {
beforeSave: async ({ adminUser, record }: { adminUser: AdminUser, record: any }) => {
record.realtor_id = adminUser.dbUser.id;
return { ok: true, record };
}
}
}
}

List of entities

For example we can prevent the user to see Apartments created by other users. Superadmin user still can see all:

./resources/apartments.ts
{
...
hooks: {
list: {
beforeDatasourceRequest: async ({
query, adminUser, resource,
}: {
query: any; adminUser: AdminUser; resource: AdminForthResource;
}) => {
if (adminUser.dbUser.role === "superadmin") {
return { ok: true };
}
if (!query.filters || query.filters.length === 0) {
query.filters = [];
}
// skip existing realtor_id filter if it comes from UI Filters (right panel)
query.filters = query.filters.filter((filter: any) => filter.field !== "realtor_id");
query.filters.push({
field: "realtor_id",
value: adminUser.dbUser.id,
operator: "eq",
});
return { ok: true };
},
},
},
}

This hook will prevent the user to see Apartments created by other users in list, however user if will be able to discover the apartment id, will be able to use show page to see the apartment details. Let's limit it as well:

By default if there is foreignResource like we use for demo on realtor_id column, the filter will suggest a select dropdown with list of all Realtors. This might be a leak to get id's of other users. Let's limit it:

./resources/apartments.ts
{
...
hooks: {
dropdownList: {
beforeDatasourceRequest: async ({ adminUser, query }: { adminUser: AdminUser, query: any }) => {
if (adminUser.dbUser.role !== "superadmin") {
query.filters = [{field: "id", value: adminUser.dbUser.id, operator: "eq"}];
};
return {
"ok": true,
};
}
},
},
}

In our case we limit the dropdown list to show only the current user, however you can use same sample to list only objects who are related to the current user in case if you will have relation configurations which require to show related objects which belongs to the current user.

Show entity

./resources/apartments.ts
{
...
hooks: {
show: {
afterDatasourceResponse: async ({
adminUser, response,
}: {
adminUser: AdminUser; response: any;
}) => {
if (adminUser.dbUser.role === "superadmin") {
return { ok: true, response };
}
if (response[0].realtor_id.pk !== adminUser.dbUser.id) {
return { ok: false, error: "You are not allowed to see this record" };
}
return { ok: true, response };
}
}
}
}

👆 Please note that we use response[0].realtor_id.pk because this fiel has foreignResource in column option is set Otherwise you would use just response[0].realtor_id

Important notice: when using hook to filter out list of items for list page or list of items on dropdown makes a lot of sense (because gives ability to change filter of database request), using hook for show page is not reasonable:

First of all it sematicaly better aligns with using allowedActions interface. For this particular case you must use allowedActions.show

Secondly limiting access from this hook will not prevent executing other hooks (e.g. beforeDatasourceRequest), when allowedActions check always performed before any hooks and any database requests.

All hooks

Check all hooks in the API reference.