You can easily define your own tags / components, as easily as creating classes. They are similar to components in react. Tags are defined with the tag
keyword:
tag App
# custom instance methods, properties etc
# create an instance of app - just like any other tag
let app = <App.main> <h1> "Hello"
var t0, Imba = require('imba'), _1 = Imba.createElement;
var App = Imba.defineTag('App');
// create an instance of app - just like any other tag
let app = (t0 = (t0=_1(App)).flag('main').setContent(t0.$.A || _1('h1',t0.$,'A',t0).setText("Hello"),2)).end();
Your custom tags will by default inherit from ‘div’, but they can inherit from any tag. You can also define instance methods on them.
# define a custom tag, inheriting from form
tag RegisterForm < form
def onsubmit event
# declare handlers as methods
console.log "submitted"
def someMethod
console.log "hello"
self
# create an instance of app - just like any other tag
let form = <RegisterForm>
form.someMethod # => "hello"
var Imba = require('imba'), _1 = Imba.createElement;
// define a custom tag, inheriting from form
var RegisterForm = Imba.defineTag('RegisterForm', 'form', function(tag){
tag.prototype.onsubmit = function (event){
// declare handlers as methods
return console.log("submitted");
};
tag.prototype.someMethod = function (){
console.log("hello");
return this;
};
});
// create an instance of app - just like any other tag
let form = (_1(RegisterForm)).end();
form.someMethod(); // => "hello"
When you declare
tag SomeComponent
you are declaring a new tag type, not an instance. It is exactly the same as declaring a newclass SomeClass
.<SomeComponent>
creates a new instance of this tag, just likeSomeClass.new
creates a new instance of said class.
Just like components in react, you can declare how custom tags should render, by declaring a render method:
tag App
def render
<self> <h1> "Hello world"
let app = <App.main>
# The DOM tree of app is now:
# <div class='App main'><h1>Hello world</h1></div>
var Imba = require('imba'), _1 = Imba.createElement;
var App = Imba.defineTag('App', function(tag){
tag.prototype.render = function (){
var $ = this.$;
return this.$open(0).setChildren($[0] || _1('h1',$,0,this).setText("Hello world"),2).synced();
};
});
let app = (_1(App).flag('main')).end();
// The DOM tree of app is now:
// <div class='App main'><h1>Hello world</h1></div>
<self>
inside render deserves some explanation. In Imba, instances of tags are directly linked to their real DOM element.<self>
refers to the component itself, and is a way of saying "now I want the content inside self to look exactly like the following. This is important to understand.
tag Wrong
def render
<h1> "Hello {Math.random}"
let wrong = <Wrong>
# wrong.render would now simply create a new h1 element
# every time it is called. The DOM element of wrong will
# still have no children.
tag Right
def render
<self> <h1> "Hello {Math.random}"
let right = <Right>
# right.render will now update its own DOM tree every time
# it is called, ensuring that the DOM is in fact reflecting
# the view declared inside <self>
var Imba = require('imba'), _1 = Imba.createElement;
var Wrong = Imba.defineTag('Wrong', function(tag){
tag.prototype.render = function (){
return (_1('h1')).setText("Hello " + (Math.random()));
};
});
let wrong = (_1(Wrong)).end();
// wrong.render would now simply create a new h1 element
// every time it is called. The DOM element of wrong will
// still have no children.
var Right = Imba.defineTag('Right', function(tag){
tag.prototype.render = function (){
var $ = this.$;
return this.$open(0).setChildren($[0] || _1('h1',$,0,this),2).synced((
$[0].setText("Hello " + (Math.random()))
,true));
};
});
let right = (_1(Right)).end();
// right.render will now update its own DOM tree every time
// it is called, ensuring that the DOM is in fact reflecting
// the view declared inside <self>
Custom tags can inherit from other custom tags, or from native tags. E.g. if you want to create a custom form component, you can simply inherit from form:
# define a custom tag, inheriting from form
tag RegisterForm < form
let view = <RegisterForm>
# the DOM element of view is now of type form.
# html: <form class='RegisterForm'></form>
var Imba = require('imba'), _1 = Imba.createElement;
// define a custom tag, inheriting from form
var RegisterForm = Imba.defineTag('RegisterForm', 'form');
let view = (_1(RegisterForm)).end();
// the DOM element of view is now of type form.
// html: <form class='RegisterForm'></form>
tag App
# declaring custom properties
prop slug
# properties with a default value
prop greeting default: 'Hello human!'
def render
<self>
<h1> "Slug is: {slug}"
if slug == '/home'
<div> "{greeting} You are home"
Imba.mount <App slug='/home'>
var Imba = require('imba'), _1 = Imba.createElement;
var App = Imba.defineTag('App', function(tag){
// declaring custom properties
tag.prototype.slug = function(v){ return this._slug; }
tag.prototype.setSlug = function(v){ this._slug = v; return this; };
// properties with a default value
tag.prototype.__greeting = {'default': 'Hello human!',name: 'greeting'};
tag.prototype.greeting = function(v){ return this._greeting; }
tag.prototype.setGreeting = function(v){ this._greeting = v; return this; }
tag.prototype._greeting = 'Hello human!';
tag.prototype.render = function (){
var $ = this.$;
return this.$open(0).setChildren([
($[0] || _1('h1',$,0,this)).setText("Slug is: " + this.slug()),
(this.slug() == '/home') ? (
($[1] || _1('div',$,1,this)).setText("" + this.greeting() + " You are home")
) : void(0)
],1).synced();
};
});
Imba.mount((_1(App).setSlug('/home')).end());