Some blog post
To create a new component all you have to do is just to create two files with the same name: ComponentName.html for template and ComponentName.php for code logic.
Please note: both files should be in the same folder.
Inside your php file create a class derived from Viewi\BaseComponent
For example, let's create Counter component.
viewi-app/Components/Views/Counter/Counter.php
<?php namespace Components\Views\Counter; use Viewi\BaseComponent; class Counter extends BaseComponent { public int $count = 0; public function increment() { $this->count++; } }
viewi-app/Components/Views/Counter/Counter.html
<button (click)="increment()">Clicked $count times.</button>
From now on you can use it as a tag with the same name as class name: <Counter />
You can reuse components as many times as you want. Each of them will have their own scope of data and reactive flow. For example:
<Counter /> <Counter /> <Counter />
The result:
You can pass data to the child component using html attributes. It can pass literals like strings, numbers, booleans or you can pass expression. For example, let's create HelloMessage component:
HelloMessage.php
<?php namespace Application\Components\Views\Demo\SimpleComponent; use Viewi\BaseComponent; class HelloMessage extends BaseComponent { public string $name; }
HelloMessage.html
<div>Hello $name</div>
And now we can pass data to the component as a custom attribute:
<HelloMessage name="John Smith" /> <HelloMessage name="Viewi" /> <HelloMessage name="{getFullName()}" />
The result:
In case you want to define your component name dynamically at runtime you can use dynamic component syntax. For example:
class ComponentsBasics extends BaseComponent { public $currentPage = 'HelloMessage'; ... <$currentPage name="Dynamic Component" />
The result:
Quite often you will need to pass content into child component through inner HTML like this:
<Notification> <i>Karolina</i> sent you a message. </Notification>
This can be easily achieved with a special slot tag, like this:
Notification.html
<div> <strong>New notification:</strong> <slot></slot> </div>
The result:
Sometimes you will need to pass different contents into different places to render. A good example for this case is layout. Consider we want something like this:
<div class="header"> <!-- header content here --> </div> <main> <!-- main content here --> </main> <footer> <!-- footer content here --> </footer>
For that cases slot tag can be used with a name attribute to define whether each content belongs to. To specify content for each slot use slotContent tag with a nameattribute. Easy, content from slotContent goes to slot with the same name. The rest of the content (outside slotContent) goes to slot without nameattribute (slot by default). For example:
BaseLayout.html
<div class="header"> <slot name="header"></slot> </div> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer>
Using:
<BaseLayout> <slotContent name="header"> This is my header content </slotContent> <p> Some blog post </p> <slotContent name="footer"> <p>Some footer links and copyright</p> </slotContent> </BaseLayout>
The result:
Some blog post
Sometimes it's useful to set a default content in case if no content is provided. Just place fallback content inside slot tag:
<button> <slot>Submit</slot> </button>
Then use it without content:
<SubmitButton></SubmitButton>
Will generate:
Or within provided content:
<SubmitButton> Save </SubmitButton>
Will generate:
You can use foreach with components as well as if, else, else-if:
PostComponent:
class PostComponent extends BaseComponent { public string $content; } ... <p>$content</p>
Usage:
class ComponentsBasics extends BaseComponent { public array $posts = [ 'Viewi is awesome!', 'Lorem ipsum dolor sit amet' ]; ... <PostComponent foreach="$posts as $post" content="$post"></PostComponent>
Will generate:
Viewi is awesome!
Lorem ipsum dolor sit amet
And this:
<PostComponent if="true" content="Viewi is awesome!"></PostComponent>
Will generate:
Viewi is awesome!
Every Viewi component goes through couple of steps during its lifecycle. It is possible to run custom code during these steps using lifecycle hooks. There it is a list of available lifecycle hooks at this moment:
Hook | Description |
---|---|
__init | Runs immediately a component is instantiated. Can accept dependency injected services and route parameters. |
__beforeMount | Runs after __init and before props (passed through attribute values) are set to the component. |
__mounted | Runs right after props (passed through attribute values) have been set to the component. |
This section is about injecting any sort of services and using models inside you components.
To be continued.