Using Advect Views
Unlike reactive frameworks like React/Vue/Angular; Advect seperates the concerns of component definition and templating
The adv-view
and adv-shadow-view
provide templating for your site and can be used standalone or within your custom elements.
Eta.js is used for rendering with the following configuration. check out Eta's Template Syntax & Cheatsheet
new Eta({
useWith: true, // Removes the "it" part of the renderer
tags: ['{{','}}'], // This changes the default start and end tags from <% %> to {{ }}
parse: {
exec: ">", // normally an empty string.
interpolate: "", //
raw: "~" // this is unchanged.
}
})
These components can be stateful using a copy of zustand that comes with the library
The AdvectView Component
<adv-view data-name="john">
<!--any html can go here-->
<output>
<!--Results Will render here-->
</output>
<template>
<!-- The markup you want templated goes here -->
Hello {{$self.data.name}}
<!-- This will render a variable {{ someVariable }} -->
<!-- This will render a rawstring {{~ someVariable }} -->
<!-- This will NOT render but execute the code within {{> console.log(someVariable)}} -->
</template>
</adv-view>
The adv-view
uses the light-dom, and expects a output
and a template
adv-view
use Eta.js
for rendering with a bit of syntactic sugar to help you layout your templates. This example will render Hello John to the output
element
Templates are rendered with a single variable $self
which in this context refers to the advect-view being rendered.
on the $self
you'll find the attr
property and the data
property which are proxies to access attributes, and dataset respectively.
Setting an attribute via either of these 2 properties will cause the adv-view
to rerender.
The AdvectShadowView Component
<adv-shadow-view data-name="john">
<!--any html can go here-->
Hello {{$self.data.name}}
</adv-shadow-view>
The adv-shadow-view
uses the shadow-dom, and unlike the <adv-view>
component does not need the output
or template
The markup for the template exists in the light-dom, and is rendered to the shadow-dom. Choosing to use the shadow-dom comes with a few benefits and drawbacks.
Benefits- Smaller Component footprint not requiring
output
ortemplate
in the view - Elements are insulated from styles that are loaded in the document
- Events need to be "composed" to propagate outside the element
- Elements ARE insulated from styles that are loaded in the document, which can be hinder your styling efforts.
Using <if> element
<template id="simple-counter" adv>
<div class="display:flex; gap:10px;">
<button ref onclick="refs.counter.data.count--">Subtract</button>
<adv-view ref="counter" onload="$this.data.count = 0">
<output></output>
<template>
<span>{{ $self.data.count }} - </span>
<if check="$self.data.count < 10">
Low Value
<else />
High Value
</if>
</template>
</adv-view>
<button ref onclick="refs.counter.data.count++">Add</button>
</div>
</template>
<simple-counter />
The <if>
virtual element is a conditional rendering mechanism that dynamically displays content based on a specified condition. It evaluates the expression provided in the check
attribute and renders the corresponding content accordingly. Here's how it works in this context:
Using <for> element
<template id="a-loop-example" adv>
<adv-view ref onload="$this.store.setState({
users:[
{ name: 'John Wick', email: 'john.wick@assassins.net', status: 'avenging'},
{ name: 'John Cena', email: 'john.cena@cantseeme.org', status: 'invisible'},
{ name: 'John Doe', email: 'john.doe@unidentified.io', status: 'missing'},
]
})">
<output></output>
<template>
<for data="$self.state.users" name="data" index="user_ind">
<div style="display:flex; gap:1em;">
<span>{{user_ind}}</span>
<span>{{user.name}}</span>
<span>{{user.email}}</span>
<span>{{user.status}}</span>
</div>
</for>
</template>
</adv-view>
</template>
<a-loop-example />
The <for>
is a virtual element for looping over Arrays and array-like objects
The for element takes 3 attributes
data
The data for the for loop.$self
in this context refers to the<adv-view>
elementname
The name to use for value accessed in the loopindex
The index of the item loop
Using <of> element
<template id="an-of-example" adv>
<adv-view ref
onload="$this.store.setState({ myObject:{ name:'John Wick', hobby:'murder' } })">
<output></output>
<template>
<for data="$self.state.myObject" name="key" value="val">
<div>{{key}}:{{val}}</div>
</for>
</template>
</adv-view>
</template>
<an-of-example />
The <of>
is a virtual element for looping over Objects properties
The for element takes 3 attributes
data
The object to loop over the properties of$self
in this context refers to the<adv-view>
elementname
The name of the propertyvalue
The value of the property
Rendering Tables
Due to how most browsers parse the <table>
elements to render a table in the <adv-view>
& <adv-shadow-view>
components you will need to use virtual elements in your templates
Below are the subsitutions that will be needed in your views to support tables.
- For
<table>
use<t-table>
- For
<thead>
use<t-head>
- For
<tbody>
use<t-body>
- For
<tfoot>
use<t-foot>
- For
<tr>
use<t-r>
- For
<th>
use<t-h>
- For
<td>
use<t-d>
<template id="a-table-example" adv>
<adv-view ref
onload="
$this.store.setState({
users:[
{ name: 'John Wick', email: 'john.wick@assassins.net'},
{ name: 'John Cena', email: 'john.cena@cantseeme.org'},
{ name: 'John Doe', email: 'john.doe@unidentified.io'},
]
})">
<div output></div>
<template>
<t-table class="table">
<t-head>
<t-r>
<of data="$self.state.users[0]" name="key" value="val">
<t-h>{{key}}</t-h>
</of>
</t-r>
</t-head>
<t-body>
<for data="$self.state.users" name="user" index="user_ind">
<t-r>
<t-d><span>{{user.name}}</span></t-d>
<t-d><span> {{user.email}} </span></t-d>
<t-d> <span> {{user.status}} </span></t-d>
</t-r>
</for>
</t-body>
</t-table>
</template>
</adv-view>
</template>
<a-table-example />