Skip to main content
Version: 3.0.0-beta

Dynamic collections

FireCMS offers the possibility to define collections dynamically. This means that collections can be built asynchronously, based on the logged-in user, based on the data of other collections, or based on any other arbitrary condition.

Instead of defining your collections as an array, use a EntityCollectionsBuilder, a function that returns a promise of an object containing the collections.

import { EntityCollectionsBuilder } from "@firecms/core";

// ...

const collectionsBuilder: EntityCollectionsBuilder = async ({
user,
authController,
dataSource
}) =>
({
collections: [
buildCollection({
path: "products",
properties: {}, // ...
name: "Products"
})
]
});
note

If you want to make customizations at the property level only, check the conditional fields section. But note that conditional fields are not suitable for asynchronous operations.

Fetch data from a different collection

It may be the case that a collection config depends on the data of another one. For example, you may want to fetch the enum values of a property from a different collection.

In this example we will fetch data from a collection called categories and use it to populate the enum values of a property called category, in the products collection.

import { useCallback } from "react";
import { buildCollection, EntityCollectionsBuilder } from "@firecms/core";

const collectionsBuilder: EntityCollectionsBuilder = async ({
user,
authController,
dataSource
}) => {

// let's assume you have a database collection called "categories"
const categoriesData: Entity<any>[] = await dataSource.fetchCollection({
path: "categories"
});

return {
collections: [
buildCollection({
id: "products",
path: "products",
properties: {
// ...
category: {
dataType: "string",
name: "Category",
// we can use the enumValues property to define the enum values
// the stored value will be the id of the category
// and the UI label will be the name of the category
enumValues: categoriesData.map((category: any) => ({
id: category.id,
label: category.values.name
}))
}
// ...
},
name: "Products"
})
]
}
};

Use in conjunction with authentication

The AuthController handles the auth state. It can also be used to store any arbitrary object related to the user.

A typical use case is to store some additional data related to the user, for example, the roles or the permissions.

import { useCallback } from "react";

const myAuthenticator: Authenticator<FirebaseUserWrapper> = useCallback(async ({
user,
authController
}) => {

if (user?.email?.includes("flanders")) {
throw Error("Stupid Flanders!");
}

console.log("Allowing access to", user?.email);
// This is an example of retrieving async data related to the user
// and storing it in the controller's extra field.
const sampleUserRoles = await Promise.resolve(["admin"]);
authController.setExtra(sampleUserRoles);

return true;
}, []);

Then you can access the extra data in the collectionsBuilder callback.

const collectionsBuilder: EntityCollectionsBuilder = useCallback(async ({
user,
authController,
dataSource
}) => {

const userRoles = authController.extra;

if (userRoles?.includes("admin")) {
return {
collections: [
buildCollection({
path: "products",
properties: {}, // ...
name: "Products"
})
]
};
} else {
return {
collections: []
};
}
}, []);

Where to use the collectionsBuilder

In the Cloud version of FireCMS, simply add the collectionsBuilder to the collections prop of your main app config.


const collectionsBuilder: EntityCollectionsBuilder = async ({
user,
authController,
dataSource
}) => {
return {
collections: [] // your collections here
};
};

export const appConfig: FireCMSAppConfig = {
version: "1",
collections: collectionsBuilder
};

In the PRO version of FireCMS, you can use the collectionsBuilder in the useBuildNavigationController hook.

const navigationController = useBuildNavigationController({
collections: collectionsBuilder
});
Sign up to our newsletter to get the latest news and updates. No spam!