-
Notifications
You must be signed in to change notification settings - Fork 56
Creating custom FormApplications
The FormApplication
class is a very handy tool to create Application
s that manage specific objects and many modules and systems will have custom FormApplication
s.
The type definitions for FormApplication
are set in a way so that by default, when you extend the FormApplication
, you will get the correct types for all of the methods in the base implementation. In particular, this means that by default, the managed object is of type {}
and the type returned by getData
is:
{
object: {};
options: FormApplicationOptions;
title: string;
}
Obviously, that is not very helpful (it doesn't really make sense to manage an empty object) and often times, you will want to return something completely different in getData
. For that reason, it is possible to specify both the type of the managed object as well as the type returned by getData
as generic parameters. Additionally, it is also possible to specify the type of the options (in case you have additional custom options in your FormApplication
) and for technical reasons, this is actually the first generic parameter.
In order to use a custom type for the options, simply provide the custom type as first generic parameter to FormApplication
when extending it. Any such custom type must extend FormApplicationOptions
.
interface MyCustomOptions extends FormApplicationOptions {
someCustomOption?: number;
}
class MyFormApplication extends FormApplication<MyCustomOptions> {
someFunction() {
// can access this.options.someCustomOption here
}
protected async _updateObject(event: Event, formData?: object): Promise<void> {
// properly update the managed object
}
}
const myFormApplication = new MyFormApplication({}, { someCustomOption: 42 });
In order to use a custom type for the return type of getData
, pass it as the second generic parameter to FormApplication
when extending it. It can be any type that extends object
. You can extend FormApplication.Data
(to which you need to provide the type of the managed object and the type of the options as generic parameters) if you want but it is completely optional and you can also just roll with your own thing.
In your getData
function, you must then return something of the specified type or a promise that resolves to something of the specified type (allowing you to make getData
async
if you want).
interface MyData {
foo: string;
bar: number;
}
class MyFormApplication extends FormApplication<FormApplicationOptions, MyData> {
getData(): MyData {
return {
foo: "some string",
bar: 42,
};
}
protected async _updateObject(event: Event, formData?: object): Promise<void> {
// properly update the managed object
}
}
In order to use a custom type for the managed object, you have two options:
- Use a type that extends
FormApplication.Data
as second parameter to theFormApplication
when extending it and pass the type of the managed object as second parameter toFormApplication.Data
(remember, the first one needs to be the type of the options). When doing this, the type of the managed object will correctly be inferred. - Simply pass the type of the managed object as third generic parameter to
FormApplication
when extending it. In both cases, you can use any type you want. The first variant has the benefit that you don't have to specify that many generic parameters if you want to use the structure given byFormApplication.Data
anyways. It has the downside that need to return something that matchesFormApplication.Data
in yourgetData
method, which often is not what you want. So most of the time, using the second variant is preferable (which is why we only provide an example for that variant).
interface MyManagedObject {
baz: number;
}
class MyFormApplication extends FormApplication<FormApplicationOptions, any, MyManagedObject> {
protected async _updateObject(event: Event, formData?: object): Promise<void> {
// properly update the managed object
}
}
const myFormApplication = new MyFormApplication({ baz: 42 });
interface MyCustomOptions extends FormApplicationOptions {
someCustomOption?: boolean;
}
interface MyData {
foo: string;
bar: number;
}
interface MyManagedObject {
baz: number;
}
class MyFormApplication extends FormApplication<MyCustomOptions, MyData, MyManagedObject> {
async getData(): Promise<MyData> {
return {
foo: this.options.someCustomOption ? "someCustomOption is set" : "someCustomOption is not set",
bar: this.object.baz,
};
}
protected async _updateObject(event: Event, formData?: object): Promise<void> {
// properly update the managed object
}
}
const myFormApplication = new MyFormApplication({ baz: 42 }, { someCustomOption: true });