With the MVVM pattern, the model drives the view.
For example, a view component will only be loaded if its model is defined:
export class ChildComponent {
@Input() model: modelVM | undefined;
}
@if (model) {
<p>Hello, I am the child component!</p>
}
However, it may be necessary to perform an asynchronous task when instantiating the view model, such as retrieving data from an api. If you want this data to be available when the view is loaded, you have to wait for the api's response, i.e. synchronize the front end with the api.
And this wait must occur inside the constructor, otherwise the class instance will be created immediately and the view will start loading while the datas are not available. Yes, I know there are ways to overcome this problem, but that's not the point.
In Typescript, it's not possible to declare an async constructor, but it is possible to emulate its behavior. We make the main constructor private to avoid calling it by mistake, and create a static async method that returns an instance of the class.
export class MyClass {
// class ctor is private
private constructor() {}
// static async class builder
static async newAsync(): Promise<MyClass> {
// instantiate a new class
const tmp = new MyClass();
// wait for some async completion
await someMethod();
// return class
return tmp;
}
}
// to create an instance
this.myClass = await MyClass.newAsync();
It's a pattern that I find very practical and use frequently.
You can find a working example on this repo. A click on the button simulates 3 seconds of asynchronous processing and displays a progress spinner. You'll see it's very simple and makes the code really easy to read.
Thanks for checking by.