B-js is a simple and fast behavior binding library inspired by KnockoutJS. It is created due to problems that the author has noticed within the implementation and conceptual framework of KnockoutJS, which results friction in development of simple and effective user interfaces. Here are a few highlights about how B-js differs from KnockoutJS:
-
B-js dependency management is much simpler, and faster. It does much less to accomplish the same goal. There are only two concepts to know: observable is a property that we can watch over, and computed is an observable whose value is calculated with a given function.
-
Main concept in B-js is binding behaviors to HTML elements. This enables limitless possibilities without deviating from the conceptual design of the library. KnockoutJS simply focuses on templating and data binding, which create friction when developing reusable components.
-
In B-js, the behaviors are attached in the same order they are supplied, and they are detached in the reverse order (LIFO). This enables B-js to manage behavior dependency easily. In KnockoutJS there is no such guarantee, and thus it is harder to add behaviors that depend on order.
-
Download B-js and source it via script tag.
-
Define your model in javascript.
var minions = [ {name: B.observable("Stuart"), likes:["banana"]}, {name: B.observable("Kevin"), likes:["banana", "apple"]} ];
-
Register your custom behaviors, if there are any.
function CustomBehavior(element, context, param) { this.element = element; //Any other initialization code here.. } //Called when param changes. CustomBehavior.prototype.update = function(newparam, oldparam){ this.element.title = oldparam + " --> " + newparam; //Any other tasks to perform when param is updated. } //Called when element is about to be removed. CustomBehavior.prototype.dispose = function(){ // TODO: clean up if necessary. } //Register the behavior B.Binding.register("custom", CustomBehavior)
-
Add binding statements in your html. This is just like KnockoutJS, but the binding attribute is called
data-binding
.<ul data-binding="foreach: $data"> <li><b data-binding="text: $data.name(), custom: $data.name()"></b> likes <span data-binding="text: $data.likes.join(', ')"></span> </ul>
-
Call B.bindData with your model and optionally the root element that the binding will start from. If you don't provide the second parameter, the whole page will be processed for binding.
B.bindData(mymodel);
That's it. After this point, the changes you will make to observable values will be updated automatically.
-
B.bindData()
creates the root context and uses it to process all elements that hasdata-binding
attribute. -
data-binding
attribute is parsed on each element. The format is likename: param [, name: param ...]
:- name refers to the name used for the behavior in registration.
- param is a valid javascript expression that is evaluated within the element context. Context has four properties:
$data
is the model that is bound to the element.$parent
is the model of the parent context, or null if root.$root
is the root model that was bound withB.bindData
$index
is the index of$data
within$parent
.
-
A new
B.Binding
object is created for each element and all behaviors are created and updated via call toupdate
method in the order they are listed indata-binding
attribute. -
When a param value for a behavior changes, B-js calls the
update
method on that behavior to let it process the change.
There are a list of behaviors that B-js provides out of the box.
-
css
takes an object hash where each key is a css class name and the value is a boolean indicating existence of class name. When true, the class name is added to the element, when false it is removed. -
style
takes an object hash where each key is a style name in camelCase, as you would call it on DOM, likeelement.style.backgroundColor = 'red'
. In this case the behavior parameter will be{backgroundColor: "red"}
. -
attr
takes an object hash where each key corresponds to an html attribute which will be set with the value. For instance, if the parameter is{title: "Hello"}
, then it will be like callingelement.setAttribute("title", "Hello")
. -
prop
takes an object hash where each key is a property on the DOM node to be set. This uses the DOM object to set the value, instead of setAttribute. -
event
takes an object hash where each key corresponds to an event to listen and the value corresponds to the event handler function for that event. The event handler is called with two arguments: $data and the event, likehandler($data, event)
. This allows writing your view models without DOM ties, unless you need to view the event object. -
click
takes an event handler function as a parameter and calls it when the element is clicked. As with all event handler calls in B-js, the first parameter sent to the handler is$data
. -
foreach
takes an array parameter and applies the inner html as a template to each item in the array. -
text
sets the textContent of the element with the given parameter. -
checked
takes a boolean parameter and sets the checked attribute on a check box. -
log
simply logs the given parameter to console, usingconsole.log
. This can be used to troubleshoot your bindings. -
value
takes a B.observable and uses it for two-way binding to a form element. Initially, the parameter value is set on the input. Then, when user changes the value of the input element, the observable parameter is updated with the new value. -
with
takes a parameter and makes it the$data
value for the template in its html. -
template
takes an object like{name: ..., data: ...}
.data
is any value that will be used as$data
in the template processing.name
parameter could be- a reference like
"#LoginVM"
where template will be obtained from innerHTML of the element with idLoginVM
- a relative url, where template will be obtained from a given url. Note that
XMLHttpRequest
will be used for download, so Cross-Origin requests should be considered. - a template string, which will be used as the template for generating content.
- a reference like
B-js was created with performance in mind. A more formal performance test will be created in near future, but initial tests show B-js is about 4 times faster than KnockoutJS, and about 2 times faster than AngularJS, when processing bindings for an array with 1000 elements. View the test page to see the performance comparison.
-
Jasmine 2.4 is used for test specifications. Default html SpecRunner from Jasmine is used. For bugs and issues, please specify the issue number in the test with a short description in the
it()
function. -
TBD