Views
Arkstack views are powered by Edge.js and use a familiar factory API.
Install
Full templates include @arkstack/view. If you are adding views manually, install:
npm i @arkstack/viewpnpm add @arkstack/viewyarn add @arkstack/viewViews are loaded from src/resources/views by default and use the .edge extension.
Render Views
Use the global view() helper or import it from @arkstack/view.
import { view } from '@arkstack/view';
const html = await view('welcome', {
name: 'Ada',
});Calling view() without a name returns the shared factory:
view().share({
appName: 'Arkstack',
});
view().share('year', new Date().getFullYear());
const html = await view('welcome');Use with() on a view instance when you want to skip the data argument in view(name, data):
const html = await view('welcome')
.with('name', 'Ada')
.with({ title: 'Welcome' });View Class
Use View when you prefer the static API.
import { View } from '@arkstack/view';
View.share({ appName: 'Arkstack' });
View.share('year', new Date().getFullYear());
const html = await View.make('dashboard', {
user,
});View.first() renders the first existing view from a list:
const html = await View.first(['themes.custom.dashboard', 'dashboard'], {
user,
});Check for a view before rendering:
if (View.exists('emails.welcome')) {
await View.make('emails.welcome', { user }).render();
}View Data
Renderable view instances support with():
const html = await View.make('profile')
.with({ title: 'Profile' })
.with('user', user)
.render();Shared data is available to every view rendered by the factory:
View.share('appName', 'Arkstack');
View.share({ year: new Date().getFullYear() });Validation Errors
Views always receive an errors object, so templates can safely ask for validation messages even when the current request has no errors:
@if(errors.has('email'))
<p>{{ errors.first('email') }}</p>
@endYou can pass errors directly when rendering:
await view('profile.edit', {
errors: {
email: ['Email is required'],
},
});Or share them for a group of renders:
View.share('errors', {
email: ['Email is required'],
});The view error bag supports helpers such as first, get, has, hasAny, missing, all, keys, count, toArray, and getMessages.
Session Errors
When using Arkstack HTTP sessions, import both setup entries during application boot:
import '@arkstack/http/setup';
import '@arkstack/view/setup';The HTTP setup attaches session and errors to the Clear Router context. The view setup reads those request locals and makes them available to any view rendered inside that request:
Router.post('/profile', async ({ session }) => {
session.addError('email', 'Email is required');
return await view('profile.edit');
});Inside profile/edit.edge:
<input name="email" />
@if(errors.has('email'))
<p>{{ errors.first('email') }}</p>
@endView Composers
View composers run before a view renders. Use them to attach common data to one view, many views, or every view.
View.composer('dashboard', (view) => {
view.with({ title: 'Dashboard' });
});
View.composer(['profile', 'settings'], (view) => {
view.with({ section: 'Account' });
});
View.composer('*', (view) => {
view.with({ appName: 'Arkstack' });
});Composers may also be classes or class instances with a compose() method:
class DashboardComposer {
compose(view) {
view.with('title', 'Dashboard');
}
}
View.composer('dashboard', DashboardComposer);
View.composer('profile', {
compose(view) {
view.with('title', 'Profile');
},
});Async composers are supported when rendering asynchronously. Use synchronous composers with renderSync().
Mounted View Paths
Mount another view directory when you need a custom root or named disk:
View.mount('/absolute/path/to/resources/views');
View.mount('admin', '/absolute/path/to/admin/views');
await View.make('admin::dashboard').render();Package Views
Packages can expose Edge templates from their own resources/views directory. Render them with tilde notation:
await view('~package-name.mail', {
user,
});
await view('~org/package-name.mail', {
user,
});~package-name.mail resolves to node_modules/package-name/resources/views/mail.edge.
~org/package-name.mail resolves to node_modules/@org/package-name/resources/views/mail.edge.
The public view name remains the tilde name inside composers:
View.composer('~org/package-name.mail', (view) => {
view.with('subject', 'Welcome');
});Make Views
The view package exposes a make:view command that is auto-discovered by the Arkstack console after the package is installed and built.
pnpm cmd make:view welcome
pnpm cmd make:view emails.welcomeDot notation maps to nested files under src/resources/views:
emails.welcome -> src/resources/views/emails/welcome.edge