API Reference
Static API
Naming Convention
Component
means the method belongs to both ‘Regular’ and its subClass.Regular
means the method only belongs to ‘Regular’ itself.
Component.extend
Component.extend
used to create a SubComponent that inherit from Component.
Usage:
Component.extend(options)
var Component = Regular.extend({
template:
"<div><h2 on-click={this.changeTitle(title + '1')}>{title}</h2>\
<div>{content}</div></div>",
config: function(){},
init: function(){},
changeTitle: function(title){
this.data.title = title;
}
})
Arguments
Param | Type | Detail |
---|---|---|
options | Object | options for Component. see options |
Return
SubComponent[Function]: SubClass inherit from Component
Component.implement
Usage:
Component.extend(options)
Arguments
Param | Type | Detail |
---|---|---|
options | Object | options for Component. see options |
Return
Component[Function]: Component self
Tips
if extending function by Component.extend and
you can use this.supr()
to invoke the super’s function that has the same name.
%
“Regular’s Class is rewrited from awesome ded/klass.”
Example >
var SubComponent = Component.extend({
init: function(){
this.supr() // call the super init
}
})
Component.implement({
hello: function( msg ){
this.supr( msg ) // call the super hello
}
})
new Component
Usage: new Component(options)
var component = new Component({
// ...other options
data: {
username: "leeluolee"
}
})
component.$inject('#container');
Arguments
Param | Type | Detail |
---|---|---|
options | Object | options for Component. see options |
Return
Instance of Component: see instance api
options passed during initialize time will become the instance property, means they will override the options passed by Component.extend
and Component.implement
. It should be noted that if you pass a Function, you can’t call this.supr()
any more.
options *
the options for define a Component. all property we don’t
- type: Object
template
- type: String | Selector | AST
config( data )
- type: Function
init
- type: Function
destory:
- type: Function
var Component = Regular.extend({
//.....
destroy: function(){
this.supr(); // call the super destroy
...other logic
}
})
var component = new Component();
component.destory();
name:
register this Component to its SuperComponent , make it composite in other component inherit from SuperComponent.
var Component = SuperComponent.extend({
//other options
name: 'foo1'
})
var Component2 = SuperComponent.extend({
template: "<foo1></foo1>"
})
it is a shortcut for SuperComponent.component(name, Component)
, example above equals to
var Component = SuperComponent.extend({});
SuperComponent.component('foo1', Component)
but method component
is much powerful than property name
, because, component()
can register Component extended from any SuperComponent.
var Component = Regular.extend({});
SuperComponent.component('foo1', Component)
events
- type: Object
在组件初始化前声明你需要绑定的事件. __这个在需要绑定一些内置事件时格外有用,因为你无需去重写对应的init
等方法了.
Regular.extend({
events: {
"$init": function(){
// same in component.init
},
"$destroy": function(){
// same in component.destroy
}
}
})
data
- type: Object
这个data最终会被merge到实例化传入的data中,你可以将其视为 缺省data. 不过仍然建议尽量在config中处理data字段的缺省值.
var Component = Regular.extend({
data: {
prop1: 1
}
})
var component = new Component({
data: {
prop2: 2
}
})
console.log(component.data.prop1) // ==> 1
Component.directive
Directive is similar to angular’s directive, but it is more lightweight( in other words, less powerful :)
). you can consider it as enhancement for the particular element.
Usage
Component.directive(name, definition)
Arguments
param | type | detail |
---|---|---|
name | String | directive name |
definition | Function Object | directive definition |
definition
- Function definition(elem, value) :
- elem: the target element
- value: the attributeValue.
- this: point to component self
Example (source code of builtin r-html
)
Regular.directive('r-html', function(elem, value){
this.$watch(value, function(new Value){
elem.innerHTML = new Value
})
})
The directiver-html
create a unescaped interpolation with innerHTML.
Beacuse $watch
accepts both [String] and [Expression] as the first param, so you can use r-html
in two ways.
<div class='preview' r-html='content'></div>
<!-- or -->
<div class='preview' r-html={content}></div>
If the directive need some clean work, you can return a destroy function(e.g. dom related operation) . but you dont need to $unwatch
the watcher defined in directive , regularjs record it for you and unwatch it automatically
Example
Regular.directive('some-directive', function(elem, value){
return function destroy(){
... destroy logic
}
})
Component.filter
regularjs supports the concept of “filters”, A “filter chain” is a designer friendly api for manipulating data.
regularjs also support concept called two-way filters
Usage
Component.filter(name, factory)
Syntax
{Expression|filter1: args.. | filter2: args...}
Arguments
param | type | detail |
---|---|---|
name | string | filter name |
factory | function object | factory function for creating new filter |
factory
factory.get(origin, args...)
[Function]:An Function to process the data-flow from origin to destnation
factory.set(dest, args...)
[Function]:the handle to process the data-flow back from destnation to origin . .
If factory is A Function, it will be automately become the factory.get
Example1 >
dateformat filter
// simplest date format
var filter = function(){
function fix(str){
str = "" + (str || "");
return str.length <= 1? "0" + str : str;
}
var maps = {
'yyyy': function(date){return date.getFullYear()},
'MM': function(date){return fix(date.getMonth() + 1); },
'dd': function(date){ return fix(date.getDate()) },
'HH': function(date){ return fix(date.getHours()) },
'mm': function(date){ return fix(date.getMinutes())}
}
var trunk = new RegExp(Object.keys(maps).join('|'),'g');
return function(value, format){
format = format || "yyyy-MM-dd HH:mm";
value = new Date(value);
return format.replace(trunk, function(capture){
return maps[capture]? maps[capture](value): "";
});
}
}();
Regular.filter("format", filter)
then
<p>{time| format: 'yyyy-MM-dd HH:mm'}</p>
output
<p>2014-12-31 12:30</p>
Two-way filter
Two way filter aim to help us transform the result when it back to origin data. it is just like filter transform data from origin to result.
two-way filter is useful in two-way binding. for example, use two-way filter with directive r-model
.
take {[1,2,3]|join: '-'}
for example
filter definition.
Regular.filter('join', {
//["1","2","3"] - > '1-2-3'
get: function(origin, split ){
return origin.join( split || "-" );
},
// **Important **
// "1"-"2"-"3" - > ["1","2","3"]
set: function(dest, split ){
return dest.split( split || "-" );
}
})
{array|json}
<input r-model={array|join:'-'} >
Builtin Filters
json
This is a two-way filter
example
var component = new Regular({
template: "<h2>{user|json}</h2>"
})
component.$update("user|json", "{'name': 'leeluolee', 'age': 10}")
//console.log(user) --> {'user':'leeluolee', 'age': 10}
Only Browser that support JSON API can get the json filter
last
last item in array, this is a one-way filter.
{[1,2,3]|last} ===> 3
Component.event
Usage
Component.event(name, factory)
Component.animation
register a new animation command, it is completely designed for directive r-animation
.
See Guide: animation for detail
Usage
Component.animation(name, factory)
Arguments
Param | Type | Detail |
---|---|---|
name | String | the custom animation name |
factory | Function | Factory function for creating command |
Example
Component.component
resiter a Component, make it nestable in OtherComponent.
Usage
Component.component(name, factory)
Arguments
Param | Type | Detail |
---|---|---|
name | String | the name used to insert Component in template |
factory | Component | A Component to be register |
Example >
var Pager = Regular.extend({
// other options
})
Component.component('pager', Pager)
// you can use pager as nested component
Component2 = Component.extend({
template: "<pager></pager>"
})
Component.use
Usage
Component.use(factory)
All methods introduced above(animation, directive,filter, event, implement) will have tightly dependence with particular Component, but for reusing, a plugin must be Compnent-independent, the connection should be created during the using of plugin.
so, the general plugin will be written like this:
function FooPlugin(Componenet){
Component.implement()// implement method
.filter() // define filter
.directive() // define directive
.event() // define custom event
}
var YourComponent = Regular.extend();
FooPlugin(YourComponent); // lazy bind
FooPlugin(Regular); // lazy bind to globals
For consistency, every Component have a method named use
to active a plugin. you can use the FooPlugin
like this.
YourComponent.use(FooPlugin);
// global
Regular.use(FooPlugin);
Regular.config
配置一些全局属性, 目前主要可以用来配置模板的自定义开关符号
Usage
Regular.config( settings )
Arguments
Param | Type | Detail |
---|---|---|
settings.BEGIN | String | OPEN_TAG (default: ‘{’) |
settings.END | String | END_TAG (default: ‘}’) |
Example >
change the TAG from default {}
to {{}}
Regular.config({
BEGIN: "{{",
END: "}}"
})
Regular.parse
Usage
Regular.parse(templateString, setting)
Parse a String to AST . you can use it for preparsing rgl template.
Arguments
Param | Type | Detail |
---|---|---|
templateString | String | the template going to be parsed |
settings.BEGIN | String | OPEN_TAG (default: ‘{’ |
settings.END | String | END_TAG (default: ‘}’) |
settings.stringify | Boolean | whether to stringify the AST (default: false) |
Usage
Example >
Regular.parse("<h2>{{page.title + page.desc}}</h2>", {
BEGIN: '{{',
END: '}}'
})
// output
[
{
"type": "element",
"tag": "h2",
"attrs": [],
"children": [
{
"type": "expression",
"body": "_d_['page']['title']+'-'+_d_['page']['desc']",
"constant": false,
"setbody": false
}
]
}
]
instance API
If a method has prefix $
, you should never rewrite it.
component.$inject
Injects, or inserts the component at a particular place relative to the element.
Usage
component.$inject(element[, direction])
Arguments
Param | Type | Detail |
---|---|---|
element | Node false |
reference element, if false be passed, the component will be removed from document |
direction(optional default:’bottom’) | String | The place to inject this component. Can be ‘top’, ‘bottom’, ‘after’, or ‘before’. |
Example >
imagine you already have a component like:
var component = new Component({
template: "<h2>{title}</h2>",
data: { title : "Example" }
})
var div = document.getElementById("#div");
and a html fragment
<div id="div">
<div class='child'></div>
</div>
compnent.$inject( div )
orcomponent.$inject( div, 'bottom' )
resulting html
<div id="div"> <div class='child'></div> <h2>Example</h2> </div>
compnent.$inject( div, 'top' )
resulting html
<div id="div"> <h2>Example</h2> <div class='child'></div> </div>
compnent.$inject( div, 'after' )
resulting html
<div id="div"> <div class='child'></div> </div> <h2>Example</h2>
or
component.$inject( div, 'before' )
resulting html
<h2>Example</h2> <div id="div"> <div class='child'></div> </div>
component.$inject( false )
(assume this component has been injected)entirely remove component from previous place(doesn’t destory it, you can $inject it again)
resulting html
<div id="div"> <div class='child'></div> </div>
Tips
you can call $inject
many times to move component from one place to another.
component.$watch
Registers a listener callback to be executed whenever the watched expression changes.
Usage
component.$watch(expression, callback [, options])
Arguments
Param | Type | Detail |
---|---|---|
expression | Expression | epression that is evaluated on each dirty-check loop. once change is detected ,it triggers a call to the listener. |
callback(newValue, oldValue) | Function | callback accept two param. 1. newValue: the current value of the expression; 2.oldValue: contains the previous value of expression |
Return
watchid [Number]: the watcher’s id, used for $unwatch
- expression is called on every call to $digest() ,see dirty-check in regularjs for more information
- The listener is called only when the value from the current expression and the previous call to expression are not equal. Inequality is determined according to reference inequality, strict comparison via the !== Javascript operator. if expression is evaluated to a [Array], regularjs will use Levenshtein distance to computed the differrence between oldValue and newValue.
component.$watch("user.name", function(new Value, oldValue){
alert("user.name changed from " + oldValue + " to " + new Value) ;
})
component.$unwatch
use watchid to unbind a watched Expression. generally speaking, it is rarely used, beacuse all watchers will be automatically destroied by regularjs.
Usage
var component = new Regular();
component.$watch('b', function(b){
alert('b watcher 1');
})
var id = component.$watch('b', function(){
alert('b watcher 2');
})
component.$unwatch(id);
component.$update('b', 100); // only alert 'watcher 1'
component.$update
component.$update
is used to synchronize data and view
Usage
component.$update([expr] [, value])
do updating operation, and force entering the digest
phase.
Arguments
- expr(Optional) [Expression | String | Object] -
- Expression: The Expression must be expr, see more in Expression
- String: String will be passed to Expression
- Object: multiple setting operation.
- value - value to be assign, if
expr
is a Object, it will be ignored
Example >
var component = new Regular({
template: "<h2 ref='h2' on-click={title=title.toLowerCase()}>{title}</h2>",
data: {
title: "REGULARJS"
}
});
//=> log 'REGULARJS' , with no doubt
console.log( component.$refs.h2.innerHTML )
component.data.title = "LEELUOLEE";
//=> also log 'REGULARJS', regularjs don't know the value is changed.
console.log( component.$refs.h2.innerHTML ) //
// force synchronizing data and view
component.$update()
//=> also 'REGULARJS'. synchronize now.
console.log( component.$refs.h2.innerHTML ) //
// trigger on-click event
component.$refs.h2.click();
// should log leeluolee.
// the Expression `title=title.toLowerCase()` is actived.
// when listener is done, regularjs will enter digest phase
console.log( component.$refs.h2.innerHTML ) //
you may need check $refs first
Beacuse you may need to set a complex Expression, $update also accept optional params to set the property easily, for Example
// 1. simple
component.$update("user.name", 'leeluolee')
// is equals to
component.data.user.name = 'leeluolee'
component.$update()
// 2. multiple
component.$update({
"user.name": "leeluolee",
"user.age": 20
})
// is equlas to
component.data.user.name = 'leeluolee'
component.data.user.age = 20
component.$update()
you can also use a complex expression. but the expression must be setable. but it is not efficient, we are very suggested to avoid doing this. unless you need to set value through two-way fitler. for Example.
// JSON.parse the title first.
component.$update('title|json', "{'title': 1}");
console.log(component.data.title) // => {title:1};
Warning: whatever param you passed, the digest phase will always be triggered.
component.$get
Usage
component.$get(Expression|String)
get a evaluated value from particluar Expression
Example >
component.data.username = "leeluolee"
component.data.job = "developer"
component.$get('username + ":" + job') // => leeluolee:developer
Arguments
Param | Type | Detail | |
---|---|---|---|
expression | Expression | String | Expression |
component.$refs
- type: Object
you can use attribute [ref] to mark a Node or Component, after compiling, you can use component.$refs.someRef
to find them.
Example >
component = new Regular({
template: "<input ref=input> <pager ref=pager></pager>",
init: function(){
this.$refs.input // -> the input tag
this.$refs.pager // -> the pager component
}
})
The less reference the better
component.$on
Register an event
handler fn
.
Usage
component.$on(event, fn])
Arguments
Param | Type | Detail |
---|---|---|
eventName | Object String | event name |
fn | Function | listener |
there will be multiple registering, if you pass a Object
Example >
component.$on("hello", fn1)
// multiple
component.$on({
notify: fn2,
message: fn3
})
component.$off
Usage
component.$off([event] [,fn])
Arguments
Param | Type | Detail |
---|---|---|
eventName | Object String | event name |
fn | Function | listener |
- Pass both event and fn to remove a listener.
- Only Pass event to remove all listeners on that event.
- Pass nothing to remove all listeners on all events.
component.$emit
Emit an event with variable option args.
Usage
component.$emit(eventName [, args...])
Arguments
Param | Type | Detail |
---|---|---|
eventName | Object String | event name |
args | Function | the rest of the params will be passed into the listener |
Example >
var component = new Regular();
var clickhandler1 = function(arg1){ console.log('clickhandler1:' + arg1)}
var clickhandler2 = function(arg1){ console.log('clickhandler2:' + arg1)}
var clickhandler3 = function(arg1){ console.log('clickhandler3:' + arg1)}
component.$on('hello', clickhandler1);
component.$on('hello', clickhandler2);
component.$on({
'other': clickhandler3
});
component.$emit('hello', 1); // handler1 handler2 trigger
component.$off('hello', clickhandler1) // hello: handler1 removed
component.$emit('hello', 2); // handler1 handler2 trigger
component.$off('hello') // all hello handler removed
component.$off() // all component's handler removed
component.$emit('other');
component.$mute
you can disable a component, make it away from dirty-check. In most case, you will combine it with $inject(false)
to remove it from document and make it disable. if you pass false
to it, it will be actived again with a digest
to make view and data synchronize.
Usage
component.$mute( isMute )
Argument
Param | Type | Detail |
---|---|---|
mute | Boolean | whether to disable this component(you can active it later use $mute(false)) |
Example >
var component = new Regular({
template: '<h2>{title}</h2>',
data: {
title: "hello"
}
})
//resulting html
<h2>hello</h2>
component.$mute(true) // disable it
component.data.hello = 'title changed'
component.$update();
// resulting html
<h2>hello</h2>
component.$bind
create binding with another component. it isn’t a recommended method. .
Usage
component.$bind(component2, expr1[, expr2])
Arguments
- component2
: the target component than need to bind with - expr1
: - Expression|String: the field that component need to bind
- Object: you can bind multiple fields at one time, the key represents component’s field, the value represents target’s field.
- Array: create multiple binding between component and component2 with the same field
- expr2
: the target component’s filed you need to binding. the default is expr1.
WARN
1. There is at least one Expression that is setable. If all Expressions are setable, it is a two-way binding. otherwise, it will be a one-way binding. 2. If target is not synchronous with component, it will be synchronized to component immediately.
create binding between pager components.
// insert
var pager = new Pager( {data: {total: 100, current:20}} ).$inject('#bind1');
var pager2 = new Pager( {data: {total: 50, current:2}} ).$inject('#bind1');
var pager3 = new Pager({data: {total: 100, current:20} }).$inject('#bind2');
var pager4 = new Pager({data: {total: 50, current:2}}).$inject('#bind2');
var pager5 = new Pager({data: {total: 100, current:2}}).$inject('#bind3');
var pager6 = new Pager({data: {total: 50, current:20}}).$inject('#bind3');
// style 1
pager.$bind(pager2, ['current', 'total']);
// style 2
pager3.$bind(pager4, 'current', 'current')
pager3.$bind(pager4, 'total') // the same as pager3.$bind(pager4, 'total', 'total')
// style 3
pager5.$bind(pager6, {current: "current", total: "total"});
// bind chain
var pager = new Pager({data:{total: 1000, current:1}}).$inject('#bind_chain');
for(var i = 0; i < 10; i++){
var pager = new Pager({data:{total: 1000, current:1}})
.$bind(pager, ['total', 'current'])
.$inject('#bind_chain');
}
you may want the source code of pager
Directive
regularjs provide some basic directive
directive only works for element, you can’t use directive to nested component.
on-[eventName]
you can use on-**
to bind event on element or component
Syntax
on-click={expression}
or on-click=delegateName
Arguments
Param | Type | Detail |
---|---|---|
expression | Expression or Name | if particular event is triggerd, expression will be evaluated |
Event is very important in regularjs, reference is not enough to take it into detail see Guide:event for more information.
r-model
very similar to ng-model
in angular, r-model
can help you to create two-way binding between data and the form element.
you can check the r-model-example on jsfiddle.
input、textarea
: simple text binding<textarea r-model='textarea'>hahah</textarea> <input r-model='input' />
input:checkbox
: binding the input’s checked state to a boolean type field<input type="checkbox" checked r-model={checked}> Check me out (value: {checked}) // checked = true
input:radio
: binding to input.value<input type="radio"value="option1" r-model={radio}>
select
: binding to select.value<!-- city = 1 --> <select r-model={city}> <option value="1" selected>Hangzhou</option> <option value="2">Ningbo</option> <option value="3">Guangzhou</option> </select>
r-style
r-style
is an enhancement for plain style
interpolation.
Exmaple
var app = new Regular({
template:
"<button class='btn'\
on-click={left=left+10} r-style={ {left: left+'px'} } >\
left+10 \
</button>\
left: {left}",
data: {left:1}
}).$inject(document.body)
Description
Param | Type | Details |
---|---|---|
r-style | expression |
Expression will eval to an object whose keys are CSS style names and values are corresponding values for those CSS keys. |
Warning: if there is already an interpolation on
style
, ther-style
will be overriddenfor examle .
<div style='left: {left}px' r-style='{left: left+"px"}'></div>
r-class
simmilar to r-style
. r-class
is an enhancement for plain class
interpolation,
Example
<div r-class='{"active": page === "home"}'></div>
in this example, when page === 'home'
, the active
will attach to the nodediv
, or vice versa.
Description
Param | Type | Details |
---|---|---|
r-class | expression |
Expression eval to Object : a map of class names to boolean values. In the case of a map, the names of the properties whose values are true will be added as css classes to the element. |
Warning: just like
r-style
, if there is already an interpolation onclass
, ther-class
will be overridden
r-hide
Exmaple
<div r-hide="page !== 'home'"></div>
if the Expression page !== 'home'
is evaluated to true, the display:none
will attach to the div
.
r-html
unescaped interpolation use innerHTML. beware of attack like xss
.
Example
<div class='preview' r-html={content}></div>
r-animation
Other
Regular.dom
Regularjs implement some cross-platform method for internal implementation needs.
Regular.dom.inject(element, refer, direction)
component.$inject
is based on this method
Arguments
Param | Type | Detail |
---|---|---|
element | Node false |
element be injected |
refer | Node false |
reference element |
direction(optional default:’bottom’) | String | The place to inject this component. Can be ‘top’, ‘bottom’, ‘after’, or ‘before’. |
Regular.dom.on(element, event, handle)
add a eventlisener on specifed element. the following property on event object has been fixed. you can use them at IE6-8. the this
in handle is point to element.
- event.target
- event.which
- event.pageX
- event.pageY
- event.stopPropagation();
- event.preventDefault();
Example >
var dom = Regular.dom;
dom.on(element, 'click', function(ev){
ev.preventDefault();
})
Regular.dom.off(node, event, handle)
unbind a eventListener
Regular.dom.addClass(element, className)
addClassName to specified element.
Regular.dom.delClass(element, className)
removeClassName at specified element.
Regular.dom.hasClass(element, className)
detect whether element has some className.
<div class='class1 class2'></div>
dom.hasClass(element, 'class1') // => true
Regular.dom.text(element[, value])
set the content of element to the specified text. if value is not passed, return the combined text contents of element
Regular.dom.html(element[, value])
set or get the innerHTML of element.
Regular.dom.attr(element, name [ , value])
Set or Get the value of an attribute for the element.