Presenter
import: @azure-net/kit/edges
There are two types of presenters - createPresenter and createPresenterFactory, presenters are providers of UI logic for components. Most UI logic that you can store outside the component is better to store in the presenter, and also implement methods for communicating with the application layer. One of the main features is that presenters fully support SSR and on the server side they are created in a separate context using AsyncLocalStorage, this allows you not to worry that your variables and states will leak between users, everything in the presenter is completely SSR-safe. It is important to note that to work with presenters in an SSR project you must configure edges-svelte using edgesHandle (see the Project Setup section). Presenter caching allows you to not reinitialize presenters with each new call, which can speed up reinitialization many times over. The implementation allows you to use presenters inside presenters and inject them into each other, it is also important to understand that when calling a presenter you must be in an individual user context created through asyncLocalStorage, if you are on the server side, or on the client, if you are on the client side, which means do not call them at the top level of ts files, call them inside components, other presenters and functions that you call inside components or presenters. Calling a presenter outside the user context (AsyncLocalStorage) on the server side will cause errors. Presenters can be generated using @azure-net/cli.
createPresenter
This is the basic type of presenter that accepts a unique project-wide key as a name, as well as a factory function inside which we describe and return our UI logic.
createPresenterFactory
This is a factory for creating presenters. The main task of this method is to create presenters with dependencies already added. Suppose you have some function that you use constantly in all presenters, then it's easier for you to add it to createPresenterFactory, and then create providers using this factory. You can store the list of presenters created using factories in core/presenters. Also note that creating presenters using factories is the preferred method of working with presenters, because at the start you may not need dependencies, but after some time you may need them, so you should take care of this in advance. Also you will lose quite a few features of the package if you do not use AsyncHelpers (more about them in the sections below), it is recommended at the initial stage to create a presenter through a factory and add them as dependencies.
Examples and Description
const AuthPresenter = createPresenter(`ContextNameAuthPresenter`, () => {
const { AuthService } = ApplicationProvider();
const modal = modalManager();
const login = async (request: ILoginRequest) => await AuthService.login(request);
const showLoginModal = () => {
modal.show({component: LoginModalComponent, options: {name: 'LoginModal'}});
};
// Everything you return you can now use in components.
return {login, showLoginModal};
});
const {login, showLoginModal} = AuthPresenter(); // In a component or another presenter
// Creating a factory
import { createPresenterFactory } from '@azure-net/kit/edges';
import { createAsyncHelpers, createErrorParser } from '@azure-net/kit';
export const ErrorHandler = createErrorParser();
export const AsyncHelpers = createAsyncHelpers({ parseError: ErrorHandler }); // returns an object like { createAsyncResource, createAsyncAction }
// Now using AppPresenter to create a presenter you will be able to get access to AsyncHelpers and handleError in each presenter
export const AppPresenter = createPresenterFactory({ ...AsyncHelpers, handleError: ErrorHandler });
// Complete example of a presenter for CRUD based on a presenter created using a factory
// Descriptions of error parser and AsyncHelpers are in the sections below, as well as a full description of what's happening below
import { AppPresenter } from '$core/presenters';
import { ApplicationProvider } from '$web/application';
import { CreateScriptSchema, UpdateScriptSchema } from './schema';
import { refreshAsyncSignal } from '@azure-net/kit';
import { modalManager, notificationManager } from '$widgets';
import type { IScript, IScriptCollectionQuery, IScriptCreateRequest, IScriptUpdateRequest } from '$web/domain/script';
export const ScriptPresenter = AppPresenter('ScriptPresenter', ({ createAsyncResource, createAsyncAction }) => {
const { ScriptService } = ApplicationProvider();
const { show } = modalManager();
const { success: successNotification } = notificationManager();
const signalKeys = {
collection: 'ScriptCollectionSignal',
resource: 'ScriptResourceSignal'
};
const collection = async (query?: IScriptCollectionQuery) => await createAsyncResource(() => ScriptService.collection(query));
const resource = async (id: number) => await createAsyncResource(() => ScriptService.resource(id));
const create = async (request: Partial<IScriptCreateRequest>) =>
await createAsyncAction<IScript, IScriptCreateRequest>(() => ScriptService.create(CreateScriptSchema.from(request).json()), {
onSuccess: () => {
successNotification('shared.notifications.created');
}
});
const update = async (id: number, request: Partial<IScriptUpdateRequest>) =>
await createAsyncAction<IScript, IScriptUpdateRequest>(() => ScriptService.update(id, UpdateScriptSchema.from(request).json()), {
onSuccess: () => {
successNotification('shared.notifications.updated');
}
});
const remove = async (id: number) =>
await createAsyncAction(() => ScriptService.remove(id), {
onSuccess: () => {
successNotification('shared.notifications.deleted');
}
});
const showRemoveModal = async (resourceId: number) => {
show({
component: (await import('$components/shared/ConfirmModal/Component.svelte')).default,
props: {
onConfirm: async () => {
await remove(resourceId);
void refreshAsyncSignal(signalKeys.collection);
}
}
});
};
return { collection, resource, create, update, remove, signalKeys, showRemoveModal };
});