Typical JavaScript frameworks require you to write a lot of extra code. From learning frameworks like Vue js, to the fact that your SEO will suffer, it's just more trouble than it's worth.
When developing a web application, you either use a javascript framework or go with a backend template engine and lose reactivity. To get both at the same time requires some complex manipulations, and it's not always efficient.
Viewi allows you to create reactive web applications using your favorite PHP. It converts your code into native javascript code to run it in the browser. This way, you get a perfectly rendered HTML page on the first load, and at the same time, your page will remain reactive without requesting each next page on link clicks, etc.
It's a new approach to writing web applications that target both sides: server and browser. Do not sacrifice one for another.
Viewi takes your components with templates and converts them into special HTML tokens and JavaScript code. This way you don't need to duplicate your logic twice. And it keeps to be SEO friendly and fully dynamic out of the box.
Viewi is not bound to specific framework and has its own template engine which is so simple to use. It also has built in Router and renders new pages without interaction with the server.
<?php namespace Application\Components\Views\Demo\TodoApp; use Viewi\BaseComponent; use Viewi\DOM\Events\DOMEvent; class TodoApp extends BaseComponent { public string $text = ''; public array $items = []; public function handleSubmit(DOMEvent $event) { $event->preventDefault(); if (strlen($this->text) == 0) { return; } $this->items[] = $this->text; $this->text = ''; } }
var TodoApp = function () { var $this = this; this.text = ''; this.items = []; this.handleSubmit = function (event) { event.preventDefault(); if(strlen($this.text) == 0) { return ; } $this.items.push($this.text); notify($this.items, 'push'); $this.text = ''; }; };
Html template
<div> <h2>Todo</h2> <form (submit)="handleSubmit($event)"> <label for="new-todo">What needs to be done?</label> <input id="new-todo" type="text" model="$text" autocomplete="off"> <button> Add #{count($items) + 1} </button> </form> <TodoList items="$items" /> </div>
We won't send you spam. Unsubscribe at any time.
Viewi component takes all the input data and assigns them to public properties. To render property in the HTML just use it as a PHP variable.
<?php namespace Application\Components\Views\Demo\SimpleComponent; use Viewi\BaseComponent; class HelloMessage extends BaseComponent { public string $name; }
<div>Hello $name</div>
<HelloMessage name="James" />
Viewi component can maintain its state and update the view once it is changed.
<?php namespace Application\Components\Views\Demo\TimerComponent; use Viewi\BaseComponent; use Viewi\Components\Services\ClientTimer; class Timer extends BaseComponent { public ClientTimer $timer; public int $seconds = 0; public int $timerId = 0; public function __init(ClientTimer $timer) { $this->timer = $timer; $this->timerId = $timer->setInterval(fn () => $this->tick(), 1000); } public function __destroy() { $this->timer->clearInterval($this->timerId); } public function tick() { $this->seconds++; } }
<div> Seconds: $seconds </div>
<Timer />
Components in Viewi react to events caused by browser or user interactions. Any PHP expression can be easily assigned as an event handler. All the changes will update HTML accordingly.
<?php namespace Application\Components\Views\Demo\ReactiveComponent; use Viewi\BaseComponent; class Counter extends BaseComponent { public int $count = 0; public function increment() { $this->count++; } }
<button (click)="increment()">Clicked $count times.</button>
<Counter />
By combining different components together we can create a simple Todo application. Each component will have its own logic without affecting the parent application. Data can be passed to the child component through properties. Event handlers track all the changes that user has made.
<?php namespace Application\Components\Views\Demo\TodoApp; use Viewi\BaseComponent; use Viewi\DOM\Events\DOMEvent; class TodoApp extends BaseComponent { public string $text = ''; public array $items = []; public function handleSubmit(DOMEvent $event) { $event->preventDefault(); if (strlen($this->text) == 0) { return; } $this->items[] = $this->text; $this->text = ''; } }
<div> <h2>Todo</h2> <form (submit)="handleSubmit($event)"> <label for="new-todo">What needs to be done?</label> <input id="new-todo" type="text" model="$text" autocomplete="off"> <button> Add #{count($items) + 1} </button> </form> <TodoList items="$items" /> </div>
<?php namespace Application\Components\Views\Demo\TodoApp; use Viewi\BaseComponent; class TodoList extends BaseComponent { public array $items; }
<ul> <li foreach="$items as $item">$item</li> </ul>
<TodoApp />
Viewi allows you to use custom JavaScript which makes it possible to integrate with external libraries and frameworks. For example, using marked library we convert the text into markdown HTML in real time.
marked.min.js
... <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> ...
<?php namespace Application\Components\Views\Demo\ExternalIntegration; use Viewi\BaseComponent; class MarkdownJs extends BaseComponent { public string $markText = '# Marked in browser\n\nRendered by **marked**.'; public function getMarkedHtml($text){ // to insert custom javascript // just use heredoc syntax with `javascript` keyword <<<javascript return marked.parse(text); javascript; } }
<h3>Input</h3> <label for="markdown-text"> Enter some markdown </label> <textarea id="markdown-text" model="$markText"></textarea> <h3>Output</h3> <div>{{getMarkedHtml($markText)}}</div>
<MarkdownJs />