View Class
The View class supports tools necessary for HTML templating, HTMLElement creation, and event handling, and is used when creating UI components.
Definition
import { View } from 'rune-ts';
interface SwitchData {
on: boolean;
}
class SwitchView extends View<SwitchData> {
override template() {
return html`
<button class="${this.data.on ? 'on' : ''}">
<div class="toggle"></div>
</button>
`;
}
}
Create
new (data: T) => View<T>;
The passed data
is registered as this.data
and passed to the template()
method like this.template(data: T);
.
new SwitchView({ on: false });
template()
protected template(): Html;
Inside the template
method, use html
to create an HTML template. (More on Template API)
import { View, html } from 'rune-ts';
class DessertView extends View<{ name: string; rating: number }> {
override template() {
return html`
<div>
<div class="name">${this.data.name}</div>
<div class="rating">${this.data.rating}</div>
</div>
`;
}
}
toHtml()
public toHtml(): string;
const dessertView = new DessertView({ name: 'Choco', rating: 2.8 });
dessertView.toHtml();
<div class="DessertView">
<div class="name">Choco</div>
<div class="rating">2.8</div>
</div>
data
public data: T;
dessertView.data.name = 'Latte';
dessertView.data.rating = 3.5;
dessertView.toHtml();
<div class="DessertView">
<div class="name">Latte</div>
<div class="rating">3.5</div>
</div>
render()
public render(): HTMLElement;
Internally, it creates an HTML string using this.template(this.data)
and returns the created HTMLElement stored in this._element
.
const element: HTMLElement = dessertView.render();
// div.DessertView
element()
public element(): HTMLElement;
Returns the already created HTMLElement.
const element: HTMLElement = dessertView.element();
// div.DessertView
isRendered()
public isRendered(): boolean;
isRendered()
checks if an HTMLElement has been created inside the View. It's useful for differentiating code that should only run in a rendered state.
renderCount
public renderCount: number;
Counts how many times the template()
function has been executed internally. This property can be utilized to implement lazy rendering by defining the template()
function to only partially render.
hydrateFromSSR()
public hydrateFromSSR(element: HTMLElement): this;
Rehydrates a View using the same data that was used to render an HTML-drawn HTMLElement. (Tutorial - Solo Component SSR)
// Server Side
new ProductView({
name: 'Phone Case',
price: 13,
}).toHtml();
// Client Side
new ProductView({
name: 'Phone Case',
price: 13,
}).hydrateFromSSR(document.querySelector('.ProductView')!);
redraw()
public redraw(): this;
Redraws the View object according to its current data state. The default behavior is to update the outermost element's html attributes, and change the interior with innerHTML
. Developers can optimize the redraw
function by overriding it.
class PhotoView extends View<{ src: string; alt: string }> {
override template({ src, alt }) {
return html`<div><img src="${src}" alt="${alt}" /></div>`;
}
override redraw() {
const img = this.element().querySelector('img')!;
img.setAttribute('src', this.data.src);
img.setAttribute('alt', this.data.alt);
}
}
The above code can be written more concisely using Rune's DOM manipulation helper class $Element
.
override redraw() {
$(this.element()).find('img')!.setAttributes(this.data);
}
subView()
protected subView<T extends ViewConstructor>(
SubView: T,
selector?: string
): InstanceType<T> | null;
Returns the first subView created within the template()
method that matches the constructor passed as an argument. The optional second argument, selector,
allows for further querying conditions using a CSS Selector.
class ProductView extends View<Product> {
override template(product: Product) {
return html`
<div>
${new PhotoView({ src: product.thumbnail, alt: product.name })}
<div class="name">${product.name}</div>
<div class="price">$${product.price}</div>
</div>
`;
}
override onRender() {
console.log(this.subView(PhotoView)!.data.src);
}
}
subViews()
protected subViews<T extends ViewConstructor>(
SubView: T,
selector?: string
): InstanceType<T>[];
Returns an array of subViews.
subViewIn()
protected subViewIn<T extends ViewConstructor>(
selector: string,
SubView: T
): InstanceType<T> | null;
Returns a single subView drawn inside a parent element found using the selector.
subViewsIn()
protected subViewsIn<T extends ViewConstructor>(
selector: string,
SubView: T,
): InstanceType<T>[];
Returns an array of subViews drawn inside a parent element found using the selector.
redrawOnlySubViews()
protected redrawOnlySubViews(): this;
Iterates through subViews and executes their redraw()
.
chain()
chain(f: (this: this, view: this) => void): this;
view.chain((view) => view.data.quantity++).redraw();
view.chain((view) => view.data.quantity++).redraw();
safely()
safely(f: (this: this, view: this) => void): this;
safely(f: (this: this, view: this) => void): this {
return this.isRendered() ? this.chain(f) : this;
}
The implementation of safely
is as described above. Use it to chain code that should only operate in a rendered state.
toString()
Returns the class name of the View.
new MyView('hi').toString();
// MyView
onRender()
Executes immediately after the View's element
is created.
onMount()
Executes right after the View is added to document.body
.
onUnmount()
Executes right after the View is removed from document.body
.
Event Handling
The View class inherits event handling methods from the Base class. (API - Event Handling)