Get started - Custom directives
Custom directives
v.directive
passing the name of the directive as first parameter and a custom method as the second parameter.Simple directive
v.directive('test', (value) => console.log(`Hello ${value}`));
v.mount('body', () => <div v-test="world">div>);
$ Hello world
Getting vnodes
v.directive('test2', (v, vnode, oldVnode) => console.log(vnode, oldVnode));
v.mount('body', () => <div v-test2>Hellodiv>)
Hello
$ {
props: { 'v-test2': true },
children: [ 'Hello' ],
name: 'div',
isSVG: false,
dom: Element {...}
} undefined
Identify created or updated node
v.directive('identify-first-render', (v, vnode, oldVnode) => {
if (!oldVnode) {
vnode.children = 'First render, vnode created';
} else {
vnode.children = 'Second render, vnode updated';
}
});
v.mount('body', () => <div v-identify-first-render>div>);
First render, vnode created
Modifying children of vnodes
children
attribute of the vnode.v.directive('modify-children', (v, vnode) => vnode.children = 'Hello world');
v.mount('body', () => <div v-modify-children>Hello John Doediv>);
Hello world
Modify properties of vnodes
If the directive needs to update previous properties you need to update the property using the v.updateProperty method.
// This will update the property by place, the change is not guaranteed.
v.directive('modify-property', (value, vnode) => vnode.props.class = 'bg-success');
// This will update of the property by method, place is not important and the change is guaranteed.
v.directive('modify-property-by-method', (value, vnode) => {
vnode.props.class = 'bg-success';
v.updateProperty('class', vnode);
});
v.mount('body', () => [
<button class="bg-primary" v-modify-property>class property before directivebutton>,
<br />,
<button v-modify-property class="bg-primary">class property after directivebutton>,
<br />,
<button class="bg-primary" v-modify-property-by-method>class before directive and updated by methodbutton>
]);
Adding events
Adding events to dom
To add an event to the dom you can simply add theon${eventName}
attribute to the vnode you want to use it.v.mount('body', () => <button class="border-primary" onclick={(event, dom) => dom.innerText = `Event ${event.type} fired`}>Simple buttonbutton>);
Each fired event will trigger an update of the app. To prevent this behavior you need to cancel the event with event.preventDefault()
.Adding events to vnode
Although you can add a listener directly to the dom property of the vnode, it is a best practice to use thev.updateProperty
method to let Valyrian.js handle the add and update of the element without worry to remove the listener if the dom updates or is removed form the dom.v.directive('click', (value, vnode) => {
vnode.props.onclick = (event, dom) => dom.innerText = `Event ${event.type} fired`;
v.updateProperty('onclick', vnode);
});
v.mount('body', () => <button v-click>Simple buttonbutton>);
Adding events to other dom and leaning events (v.onCleanup)
If you want to add a listener to another dom element from within a directive you will need to remove the handler on each render using thev.onCleanup
method.This method runs the passed callback at the begining of each render.
Also you need to validate first if we are in the browser scope because in nodejs some dom methods don't exists and events can not be fired.
v.directive('listen-to-scroll', (value, vnode) => {
// We check if we are not in the browser
if (!v.isNode) {
// Get the article element
let article = document.getElementsByTagName('article')[0];
// Set the listener to a var
let listener = (e) => vnode.dom.innerText = article.scrollTop;
// Attach the listener
article.addEventListener('scroll', listener);
// If we re-render the ui remove the listener before attach it again
v.onCleanup(() => article.removeEventListener('scroll', listener));
}
});
v.mount('body', () => <span v-listen-to-scroll>span>);
Flag implementation example
let dayjs = require('dayjs');
let formatDate = (value) => dayjs(value).format('MMMM D, YYYY');
v.directive('date-inline', (date, vnode) => vnode.children = formatDate(date));
v.directive('date', (value, vnode) => vnode.children = formatDate(vnode.children[0]));
v.mount('body', () => [
<div v-date-inline="08-16-2018">div>,
<div v-date>08-16-2018div>
]);
August 16, 2018
August 16, 2018
Complex example v-switch
It works as a switch statement and needs a set of arrays as children of the form
[testCase|method, vnodes|method]
v.directive('switch', (value, vnode) => {
for (let i = 0, l = vnode.children.length; i < l; i++) {
let [test, handler] = vnode.children[i];
let result = typeof test === 'function' ?
test(value) :
value === test;
if (result) {
vnode.children = typeof handler === 'function' ? handler(value) : handler;
return;
}
}
vnode.children = value;
});
let Component = ({name}) => <div v-switch={name}>
{['John', <span>Hello Johnspan>]}
{[(val) => val === 'John Doe', <span>Hello John Doespan>]}
{['Jane', (val) => <span>Hello {val} Doespan>]}
div>;
v.mount('body', () => [
<ComplexExample name='John' />,
<ComplexExample name='John Doe' />,
<ComplexExample name='Jane' />
]);
Hello John
Hello John Doe
Hello Jane Doe