2w 5kb 2-way data binding

2w gives you a simple, small, library-agnostic 2-way data binding API, inspired by angularjs'.

Quick demo

{{ greet() }}{{ name }}!
<div data-controller="quickdemo">
    <input type="text" data-model="name" placeholder="Type your name...">
    <span>{{ greet() }}{{ name }}!</span>
</div>
$2w.controller('quickdemo', function(scope){
    scope.greet = function() {
        return 'Hello' + (scope.name ? ', ' : '');
    }
});

Quick documentation

Install

Just add 2w.js before all other scripts using 2w.

<script src="/javascripts/2w.js"></script>

And you're ready to go.

Controllers

Controllers are callbacks bound to active DOM elements. Any element with a controller attached will listen to data changes and re-render itself whenever a change occurs.

You create and set a controller using the data-controller attribute.

Once you add some controllers to the html markup, you can initialize some behaviour, using $2w.controller().

This is a simple {{text}}.

This is an active {{text}}.

<!doctype html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body>
    <p>This is a simple {{text}}.</p>
    <p data-controller="paragraph">This is an active {{text}}.</p>

    <script src="2w.js"></script>
    <script src="demo.js"></script>
  </body>
</html>$2w.controller('paragraph', function(p){
  p.text = 'text set dynamically';
});

$2w.controller() setter takes two arguments: a controller name, and a behaviour callback. This callback is executed passing the controller scope as argument. Everytime a property of the scope changes, the view is updated automatically.

If you want to change a scope property from outside the controller callback, you can access it via the $2w.controller() getter:

This is a simple {{text}}.

This is an active {{text}}.

Change paragraph2 text
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body>
    <p>This is a simple {{text}}.</p>
    <p data-controller="paragraph2">This is an active {{text}}.</p>
    <a id="link">Change paragraph2 text</a>

    <script src="2w.js"></script>
    <script src="demo.js"></script>
  </body>
</html>
$2w.controller('paragraph2', function(p){
  p.text = 'text set dynamically';
});
document.getElementById('link').addEventListener('click', function(){
  var $p = $2w.controller('paragraph2');
  $p.text = 'different text';
}, false);

Template expressions

Template expressions are simply good ol' javascript expressions. This means that you can add more than string variables to templates.

  • This is a string: {{string}}
  • This is a math operation: {{2+2}}
  • This is a function call: {{func()}}
  • This is a ternary expression: {{func() ? 'foo' : 'bar'}}
  • This is a assign expression: {{result = 5}}
  • And this is the assignment: {{result}}
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body data-controller="expressions">
    <ul>
      <li>This is a string: {{string}}</li>
      <li>This is a math operation: {{2+2}}</li>
      <li>This is a function call: {{func()}}</li>
      <li>This is a ternary expression: {{func() ? 'foo' : 'bar'}}</li>
      <li>This is a assign expression: {{result = 5}}</li>
      <li>And this is the assignment: {{result}}</li>
    </ul>

    <script src="2w.js"></script>
    <script src="demo.js"></script>
  </body>
</html>
$2w.controller('expressions', function(ctrl){
  ctrl.string = 'some text';
  ctrl.func = function() {
    return Math.random()*10 < 5;
  }
  ctrl.result = 1; // This gets overwritten
});

One callback for multiple controllers

You can also bootstrap a callback for several controllers. Pass space-separated controller names to $2w.controller() and the callback will be invoked with all of them passed as arguments.

This is {{ctrl}}

This is {{ctrl}}

<!doctype html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body>
    <div data-controller="ctrlOone">
        <p>This is {{ctrl}}</p>
    </div>
    <div data-controller="ctrlTwo">
        <p>This is {{ctrl}}</p>
    </div>

    <script src="2w.js"></script>
    <script src="demo.js"></script>
  </body>
</html>
$2w.controller('ctrlOone ctrlTwo', function(one, two){
  one.ctrl = 'controller number one';
  two.ctrl = 'controller number two';
});

Attaching controllers dynamically

You can create a controller dynamically and attach it to any document element using $2w.attachController() passing a dom element and a controller name. If the controller doesn't exist, it'll be created on the go.

This is an {{op}}: {{2+2}}

Attach controller
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body>
    <div id="dynamic">
        <p>This is an {{op}}: {{2+2}}</p>
    </div>
    <a id="link">Attach controller</a>

    <script src="2w.js"></script>
    <script src="demo.js"></script>
  </body>
</html>
$2w.controller('myCtrl', function(scope){
  scope.op = 'exprssion';
});
document.getElementById('link').addEventListener('click', function(){
  $2w.attachController(document.getElementById('dynamic'), 'myCtrl');
}, false);

Events

There are some events tied to certain attributes. For example, you can use data-click to fire an expression:

Some text: {{text}}

Change text
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body>
    <div data-controller="clickCtrl">
        <p>Some text: {{text}}</p>
        <a data-click="text = 'bar'">Change text</a>
    </div>

    <script src="2w.js"></script>
    <script src="demo.js"></script>
  </body>
</html>
$2w.controller('clickCtrl', function(scope){
  scope.text = 'foo';
});