On this page
views
introduction
dframework ships with a custom view engine. it uses a string to function evaluation model that compiles your templates into raw javascript functions. this means you can write standard javascript directly inside your templates while utilizing convenient directives for common tasks.
creating views
views are stored in the views directory and must use the .d file extension. they are referenced using dot notation. a file at views/app/home/index.d is referenced as app.home.index.
1<!-- views/greetings/hello.d -->2<html>3 <body>4 <h1>hello, {{ name }}!</h1>5 </body>6</html>you return views from your controllers using the render() helper.
1export default class GreetingController {2 async hello() {3 return render('greetings.hello', { name: 'world' });4 }5}for security reasons, you cannot pass dangerous javascript global objects (process, require, global, etc.) into your view data. the engine strictly validates the provided context and will throw an error if tampering is detected.
displaying data
you display data passed to your views by wrapping the variable in double curly braces. the view engine automatically escapes the output to prevent xss attacks.
1hello, {{ user.name }}.2the current timestamp is {{ Date.now() }}.
if you need to render unescaped html, use the {!! !!} syntax.
1{!! user.bio_html !!}
you can convert objects to json strings using the @json directive.
1<script>[object Object]>2 const userState = @json(user);[object Object]>3</script>
control structures
the view engine provides shortcuts for common javascript control structures.
if statements
1@if (user.isAdmin)2 <button>admin panel</button>3@elseif (user.isModerator)4 <button>mod panel</button>5@else6 <span>standard user</span>7@endifloops
1@foreach (users as user)2 <li>{{ user.name }}</li>3@endforeach4 5@for (let i = 0; i < 10; i++)6 <span>{{ i }}</span>7@endforthe @forelse directive is a convenient way to loop over arrays with a fallback if the array is empty.
1@forelse (tracks as track)2 <li>{{ track.title }}</li>3@empty4 <li>no tracks found.</li>5@endforelse
layouts and includes
you can define a master layout and extend it from child views. use @yield to mark where content should be injected, and @section in the child view to provide that content.
1<!-- views/layouts/app.d -->2<html>3 <head>4 <title>app</title>5 </head>6 <body>7 <nav>...</nav>8 <main>9 @yield('content')10 </main>11 </body>12</html>1<!-- views/home.d -->2@extends('layouts.app')3 4@section('content')5 <h1>welcome home</h1>6@endsectionyou can include partials using the @include directive.
1@include('components.header')
javascript execution
since the view engine compiles directly to javascript functions, you can execute arbitrary server side code directly inside your templates. use the @js() directive for a single line of javascript, or the @js ... @endjs block for multiple lines.
1@js(const maxLimit = 50;)2 3@js4 let sortedUsers = users.sort((a, b) => b.score - a.score);5 sortedUsers = sortedUsers.slice(0, maxLimit);6@endjs7 8@foreach (sortedUsers as user)9 <li>{{ user.name }}</li>10@endforeach
localization
you can translate strings using the @t() directive. the framework automatically resolves the current locale from the request context and fetches the corresponding translation string.
1<h1>@t('home.welcome_message')</h1>2<p>@t('home.unread_count', { count: 5 })</p>
pagination
the view engine includes a built in @pagination directive that automatically generates html pagination links for a paginated result object returned by the model .paginate() method.
if you leave the block empty, the engine automatically generates standard pagination controls with icons and page numbers.
1<!-- renders standard pagination controls -->2@pagination(users)3@endpaginationby default, if the request comes from the spa router (dSPAHttpRequest), the links will automatically trigger spa navigation instead of a full page reload. if you need the pagination links to update a specific dom element via the spa router (e.g. replacing just a table body), you can pass a css selector as the third argument.
1<!-- updates the #user-list container instead of a full page transition -->2@pagination(users, true, '#user-list')3@endpaginationcustom pagination html
if you provide content inside the @pagination block, the engine skips the default html generation and renders your custom html instead.
inside the block, the engine automatically exposes four variables that you can use to build your custom controls:
prev: the query string for the previous page (ornull)next: the query string for the next page (ornull)current: the current page numberlast: the total number of pages
1@pagination(users)2 <div class="custom-pagination">3 <p>page {{ current }} of {{ last }}</p>4 5 @if (prev)6 <a href="{{ prev }}" class="btn">previous</a>7 @endif8 9 @if (next)10 <a href="{{ next }}" class="btn">next</a>11 @endif12 </div>13@endpaginationthe framework evaluates the block only if there is more than one page (last > 1). if there is only one page, the entire @pagination block is skipped and nothing is rendered.
automatic form handling
when you create an html <form> with a mutating method (e.g. POST, PUT), the view engine automatically injects a hidden _csrf input field and the current csrf token value. you do not need to manually output csrf tokens in your forms.
additionally, the engine injects a <meta name="csrf-token"> tag into the document's <head>, allowing your ajax requests to pick up the token.
anti peeping protection
dframework includes a built in anti peeping script that disables context menus, blocks common developer tools keyboard shortcuts, and triggers infinite debugger loops if the console is forced open.
this behavior can be toggled globally via app.antiPeeping in your configuration, or overridden per response using the antiPeeping(false) chainable helper in your controller.
view compilation
in the local environment, the framework uses a custom jit compiler and provides detailed error traces mapped directly to your original .d files.
in the production environment, views are ahead of time compiled into highly optimized .dc (.d compiled) files. the framework verifies the cryptographic integrity of these .dc files on startup to ensure your templates have not been tampered with.

