Components are a special kind of View
that is designed to be easily composable,
making it simple to add child views and build complex user interfaces.
Unlike views, which are render-agnostic, components have a specific set of rendering
guidelines that allow for a more declarative development style.
Components are defined with the create
static method, which takes a tagged template.
Extends: Rasti.View
Param | Type | Description |
---|---|---|
options | object |
Object containing options. The following keys will be merged to this : model, state, key, onDestroy, onRender, onCreate, onChange. |
Properties
Name | Type | Description |
---|---|---|
key | string |
A unique key to identify the component. Used to recycle child components. |
model | object |
A Rasti.Model or any emitter object containing data and business logic. |
state | object |
A Rasti.Model or any emitter object containing data and business logic, to be used as internal state. |
Example
import { Component, Model } from 'rasti';
// Create Timer component.
const Timer = Component.create`
<div>
Seconds: <span>${({ model }) => model.seconds}</span>
</div>
`;
// Create model to store seconds.
const model = new Model({ seconds: 0 });
// Mount timer on body.
Timer.mount({ model }, document.body);
// Increment `model.seconds` every second.
setInterval(() => model.seconds++, 1000);
- Component ⇐
Rasti.View
- instance
- static
- .extend(object)
- .mount(options, el, hydrate) ⇒
Rasti.Component
- .create(HTML) ⇒
Rasti.Component
Lifecycle method. Called when the view is created at the end of the constructor.
Kind: instance method of Component
Param | Type | Description |
---|---|---|
options | object |
The view options. |
Lifecycle method. Called when model emits change
event.
By default calls render method.
This method should be extended with custom logic.
Maybe comparing new attributes with previous ones and calling
render when needed. Or doing some dom transformation.
Kind: instance method of Component
Param | Type | Description |
---|---|---|
model | Rasti.Model |
The model that emitted the event. |
changed | object |
Object containing keys and values that has changed. |
[...args] | any |
Any extra arguments passed to set method. |
Lifecycle method. Called when the view is rendered.
Kind: instance method of Component
Param | Type | Description |
---|---|---|
type | string |
The render type. Can be render , hydrate or recycle . |
Lifecycle method. Called when the view is destroyed.
Kind: instance method of Component
Param | Type | Description |
---|---|---|
options | object |
Options object or any arguments passed to destroy method. |
Helper method used to extend a Component
, creating a subclass.
Kind: static method of Component
Param | Type | Description |
---|---|---|
object | object |
Object containing methods to be added to the new Component subclass. Also can be a function that receives the parent prototype and returns an object. |
Mount the component into the dom.
It instantiate the Component view using options,
appends its element into the DOM (if el
is provided).
And returns the view instance.
Kind: static method of Component
Param | Type | Description |
---|---|---|
options | object |
The view options. |
el | node |
Dom element to append the view element. |
hydrate | boolean |
If true, the view will use existing html. |
Takes a tagged template containing an HTML string,
and returns a new Component
class.
- The template outer tag and attributes will be used to create the view's root element.
- Boolean attributes should be passed in the form of
attribute="${() => true}"
. - Event handlers should be passed, at the root element, in the form of
onEventName=${{'selector' : listener }}
. Whereselector
is a css selector. The event will be delegated to the view's root element. - The template inner HTML will be used as the view's template.
- Template interpolations that are functions will be evaluated on the render process. Receiving the view instance as argument. And being bound to it.
- If the function returns
null
,undefined
,false
or empty string, the interpolation won't render any content. - If the function returns a component instance, it will be added as a child component.
- If the function returns an array, each item will be evaluated as above.
Kind: static method of Component
Param | Type | Description |
---|---|---|
HTML | string |
template for the component. |
Emitter
is a class that provides an easy way to implement the observer pattern
in your applications.
It can be extended to create new classes that have the ability to emit and bind custom named events.
Emitter is used by Model
and View
classes, which inherit from it to implement
event-driven functionality.
Example
import { Emitter } from 'rasti';
// Custom cart
class ShoppingCart extends Emitter {
constructor() {
super();
this.items = [];
}
addItem(item) {
this.items.push(item);
// Emit a custom event called `itemAdded`.
// Pass the added item as an argument to the event listener.
this.emit('itemAdded', item);
}
}
// Create an instance of ShoppingCart and Logger
const cart = new ShoppingCart();
// Listen to the `itemAdded` event and log the added item using the logger.
cart.on('itemAdded', (item) => {
console.log(`Item added to cart: ${item.name} - Price: $${item.price}`);
});
// Simulate adding items to the cart
const item1 = { name : 'Smartphone', price : 1000 };
const item2 = { name : 'Headphones', price : 150 };
cart.addItem(item1); // Output: "Item added to cart: Smartphone - Price: $1000"
cart.addItem(item2); // Output: "Item added to cart: Headphones - Price: $150"
Adds event listener.
Kind: instance method of Emitter
Param | Type | Description |
---|---|---|
type | string |
Type of the event (e.g. change ). |
listener | function |
Callback function to be called when the event is emitted. |
Example
this.model.on('change', this.render.bind(this)); // Re render when model changes.
Adds event listener that executes once.
Kind: instance method of Emitter
Param | Type | Description |
---|---|---|
type | string |
Type of the event (e.g. change ). |
listener | function |
Callback function to be called when the event is emitted. |
Example
this.model.once('change', () => console.log('This will happen once'));
Removes event listeners.
Kind: instance method of Emitter
Param | Type | Description |
---|---|---|
[type] | string |
Type of the event (e.g. change ). If is not provided, it removes all listeners. |
[listener] | function |
Callback function to be called when the event is emitted. If listener is not provided, it removes all listeners for specified type. |
Example
this.model.off('change'); // Stop listening to changes.
Emits event of specified type. Listeners will receive specified arguments.
Kind: instance method of Emitter
Param | Type | Description |
---|---|---|
type | string |
Type of the event (e.g. change ). |
[...args] | any |
Arguments to be passed to listener. |
Example
this.emit('invalid'); // Emit validation error event.
- Orchestrates data and business logic.
- Emits events when data changes.
A Model
manages an internal table of data attributes and triggers change events when any of its data is modified.
Models may handle syncing data with a persistence layer. To design your models, create atomic, reusable objects
that contain all the necessary functions for manipulating their specific data.
Models should be easily passed throughout your app and used anywhere the corresponding data is needed.
Rasti models stores its attributes in this.attributes
, which is extended from this.defaults
and the
constructor attrs
parameter. For every attribute, a getter is generated to retrieve the model property
from this.attributes
, and a setter is created to set the model property in this.attributes
and emit change
and change:attribute
events.
Extends: Rasti.Emitter
Param | Type | Description |
---|---|---|
attrs | object |
Object containing model attributes to extend this.attributes . Getters and setters are generated for this.attributtes , in order to emit change events. |
Example
import { Model } from 'rasti';
// Product model
class ProductModel extends Model {
preinitialize() {
// The Product model has `name` and `price` default attributes.
// `defaults` will extend `this.attributes`.
// Getters and setters are generated for `this.attributes`,
// in order to emit `change` events.
this.defaults = {
name: '',
price: 0
};
}
setDiscount(discountPercentage) {
// Apply a discount to the price property.
// This will call a setter that will update `price` in `this.attributes`,
// and emit `change` and `change:price` events.
const discount = this.price * (discountPercentage / 100);
this.price -= discount;
}
}
// Create a product instance with a name and price.
const product = new ProductModel({ name: 'Smartphone', price: 1000 });
// Listen to the `change:price` event.
product.on('change:price', () => console.log('New Price:', product.price));
// Apply a 10% discount to the product.
product.setDiscount(10); // Output: "New Price: 900"
- Model ⇐
Rasti.Emitter
- .preinitialize(attrs)
- .defineAttribute(key)
- .get(key) ⇒
any
- .set(key, [value]) ⇒
this
- .toJSON() ⇒
object
If you define a preinitialize method, it will be invoked when the Model is first created, before any instantiation logic is run for the Model.
Kind: instance method of Model
Param | Type | Description |
---|---|---|
attrs | object |
Object containing model attributes to extend this.attributes . |
Generate getter/setter for the given key. In order to emit change
events.
This method is called internally by the constructor
for this.attributes
.
Kind: instance method of Model
Param | Type | Description |
---|---|---|
key | string |
Attribute key. |
Get an attribute from this.attributes
.
This method is called internally by generated getters.
Kind: instance method of Model
Returns: any
- The attribute value.
Param | Type | Description |
---|---|---|
key | string |
Attribute key. |
Set an attribute into this.attributes
.
Emit change
and change:attribute
if a value change.
Could be called in two forms, this.set('key', value)
and
this.set({ key : value })
.
This method is called internally by generated setters.
The change
event listener will receive the model instance, an object containing the changed attributes, and the rest of the arguments passed to set
method.
The change:attribute
event listener will receive the model instance, the new attribute value, and the rest of the arguments passed to set
method.
Kind: instance method of Model
Returns: this
- This model.
Emits: event:change
, change:attribute
Param | Type | Description |
---|---|---|
key | string |
Attribute key or object containing keys/values. |
[value] | Attribute value. |
Return object representation of the model to be used for JSON serialization.
By default returns this.attributes
.
Kind: instance method of Model
Returns: object
- Object representation of the model to be used for JSON serialization.
- Listens for changes and renders UI.
- Handles user input and interactivity.
- Sends captured input to the model.
A View
is an atomic unit of the user interface that can render the data from a specific model or multiple models.
However, views can also be independent and have no associated data.
Models must be unaware of views. Views, on the other hand, may render model data and listen to the change events
emitted by the models to re-render themselves based on changes.
Each View
has a root element, this.el
, which is used for event delegation.
All element lookups are scoped to this element, and any rendering or DOM manipulations should be done inside it.
If this.el
is not present, an element will be created using this.tag
(defaulting to div) and this.attributes
.
Extends: Rasti.Emitter
Param | Type | Description |
---|---|---|
options | object |
Object containing options. The following keys will be merged to this : el, tag, attributes, events, model, template, onDestroy. |
Properties
Name | Type | Description |
---|---|---|
el | node |
Every view has a root element, this.el . If not present it will be created. |
tag | string |
If this.el is not present, an element will be created using this.tag . Default is div . |
attributes | object |
If this.el is not present, an element will be created using this.attributes . |
events | object |
Object in the format {'event selector' : 'listener'} . Used to bind delegated event listeners to root element. |
model | object |
A Rasti.Model or any object containing data and business logic. |
template | function |
A function that receives data and returns a markup string (html for example). |
Example
import { View } from 'rasti';
class Timer extends View {
constructor(options) {
super(options);
// Create model to store internal state. Set `seconds` attribute into 0.
this.model = new Model({ seconds : 0 });
// Listen to changes in model `seconds` attribute and re render.
this.model.on('change:seconds', this.render.bind(this));
// Increment model `seconds` attribute every 1000 milliseconds.
this.interval = setInterval(() => this.model.seconds++, 1000);
}
template(model) {
return `Seconds: <span>${model.seconds}</span>`;
}
}
// Render view and append view's element into body.
document.body.appendChild(new Timer().render().el);
- View ⇐
Rasti.Emitter
- .preinitialize(attrs)
- .$(selector) ⇒
node
- .$$(selector) ⇒
Array.<node>
- .destroy() ⇒
Rasti.View
- .onDestroy(options)
- .addChild(child) ⇒
Rasti.View
- .destroyChildren()
- .ensureElement()
- .createElement(tag, attrs) ⇒
node
- .removeElement() ⇒
Rasti.View
- .delegateEvents([events]) ⇒
Rasti.View
- .undelegateEvents() ⇒
Rasti.View
- .render() ⇒
Rasti.View
If you define a preinitialize method, it will be invoked when the view is first created, before any instantiation logic is run.
Kind: instance method of View
Param | Type | Description |
---|---|---|
attrs | object |
Object containing model attributes to extend this.attributes . |
Returns the first element that match the selector,
scoped to DOM elements within the current view's root element (this.el
).
Kind: instance method of View
Returns: node
- Element matching selector within the view's root element (this.el
).
Param | Type | Description |
---|---|---|
selector | string |
CSS selector. |
Returns a list of elements that match the selector,
scoped to DOM elements within the current view's root element (this.el
).
Kind: instance method of View
Returns: Array.<node>
- List of elements matching selector within the view's root element (this.el
).
Param | Type | Description |
---|---|---|
selector | string |
CSS selector. |
Destroy the view.
Destroy children views if any, undelegate events, stop listening to events, call onDestroy
lifecycle method.
Kind: instance method of View
Returns: Rasti.View
- Return this
for chaining.
onDestroy
lifecycle method is called after view is destroyed.
Override with your code. Useful to stop listening to model's events.
Kind: instance method of View
Param | Type | Description |
---|---|---|
options | object |
Options object or any arguments passed to destroy method. |
Add a view as a child.
Children views are stored at this.children
, and destroyed when the parent is destroyed.
Returns the child for chaining.
Kind: instance method of View
Param | Type |
---|---|
child | Rasti.View |
Call destroy method on children views.
Kind: instance method of View
Ensure that the view has a root element at this.el
.
You shouldn't call this method directly. It's called from constructor.
You may override it if you want to use a different logic or to
postpone element creation.
Kind: instance method of View
Create an element.
Called from constructor if this.el
is undefined, to ensure
the view to have a root element.
Kind: instance method of View
Returns: node
- The created element.
Param | Type | Default | Description |
---|---|---|---|
tag | string |
"div" |
Tag for the element. Default to div |
attrs | object |
Attributes for the element. |
Remove this.el
from DOM.
Kind: instance method of View
Returns: Rasti.View
- Return this
for chaining.
Provide declarative listeners for DOM events within a view. If an events hash is not passed directly, uses this.events
as the source.
Events are written in the format {'event selector' : 'listener'}
. The listener may be either the name of a method on the view, or a direct function body.
Omitting the selector causes the event to be bound to the view's root element (this.el
).
By default, delegateEvents
is called within the View's constructor,
so if you have a simple events hash, all of your DOM events will always already be connected, and you will never have to call this function yourself.
All attached listeners are bound to the view automatically, so when the listeners are invoked, this
continues to refer to the view object.
When delegateEvents
is run again, perhaps with a different events hash, all listeners are removed and delegated afresh.
Kind: instance method of View
Returns: Rasti.View
- Return this
for chaining.
Param | Type | Description |
---|---|---|
[events] | object |
Object in the format {'event selector' : 'listener'} . Used to bind delegated event listeners to root element. |
Example
MyView.prototype.events = {
'click button.ok' : 'onClickOkButton',
'click button.cancel' : function() {}
};
Removes all of the view's delegated events. Useful if you want to disable or remove a view from the DOM temporarily. Called automatically when the view is destroyed.
Kind: instance method of View
Returns: Rasti.View
- Return this
for chaining.
Render the view.
This method should be overridden with custom logic.
The default implementation sets innerHTML of this.el
with this.template
.
Conventions are to only manipulate the dom in the scope of this.el
,
and to return this
for chaining.
If you added any child view, you must call this.destroyChildren
.
Kind: instance method of View
Returns: Rasti.View
- Return this
for chaining.