Skip to content
jacwright edited this page Oct 16, 2014 · 13 revisions
Chip

Getting Started

Download Chip and put it in a directory with the following HTML file.

<html>
<head>
  <script src="http://code.jquery.com/jquery-latest.js"></script>
  <script src="../dist/chip.js"></script>
</head>
<body>
<header>
  <h1>My App</h1>
</header>
<div id="main" bind-controller>
  <label>Name:</label>
  <input type="text" bind-value="name" placeholder="Enter a name here" autofocus>
  <button bind-click="window.alert(name)">Say it!</button>
  <h2 bind-if="name">Welcome <span bind-text="name"></span>!</h2>
</div>
</body>
</html>

You'll see that when you type a name in the text input the message on the page appears and updates as you type. You can probably guess what Chip is doing with the bind-* attributes by their names. We'll talk more about those attributes later.

Like other popular frameworks, data is bound automatically in the page and is updated as it changes. Unlike other frameworks, Chip is small and simple.

Routing

To create a multi-page app Chip provides routing which allows you to load up templates and controllers for each page. You define a route a url and a name, then when you hit that URL in your app the template under that name will be displayed and the controller under that name (if any) will be bound to the template. The template will show up in an element designated with an attribute "bind-route".

<html>
<head>
  <script src="http://code.jquery.com/jquery-latest.js"></script>
  <script src="../dist/chip.js"></script>
  <script>
    function homeController(controller) {
      controller.message = 'Hello!'
    }
    
    // Chip doesn't support hash urls right now, so this page needs to be delivered in a webserver pointing to the root of the repository
    chip.route('/examples/simple2.html', 'home')
    chip.route('/welcome', 'welcome')
    chip.listen()
  </script>
</head>
<body>
<header>
  <h1>My App</h1>
</header>
<div id="main" bind-route>
  <h1>An Error Occurred</h1>
  <p>You can place a message here to be displayed when JavaScript is turned off or there is a fatal JS error in the page. Or an HTML-only version of the page if you want!</p>
</div>

<script name="home" type="text/html">
  <h1 bind-text="message">message</h1>
  <p>Go see a personal <a href="/welcome">welcome message</a></p>
</script>

<script name="welcome" type="text/html">
  <label>Name:</label>
  <input type="text" bind-value="name" placeholder="Enter a name here" autofocus>
  <button on-click="window.alert(name)">Say it!</button>
  <h2 bind-if="name">Welcome <span bind-text="name"></span>!</h2>
</script>
</body>
</html>

When you go to this page you'll see "Hello!" and a link to the welcome page. That link will load up the welcome template from above. You'll be able to use hashes or HTML5 pushState eventually, but right now I haven't made time for hashes.

Models, Controllers, Views

Models

Chip allows you to build your own model layer. You can provide a service that loads and saves plain JavaScript objects and arrays, or you can create classes for each type of model object in your system and provide logic on the objects themselves.

While some people want to be told exactly how to build everything in their app, models are as custom as the business logic that drives them. Chip may provide light-weight model capabilities in the future, but jQuery.ajax should do everything you need.

Controllers

Controllers are set for the page (for the bind-route) as well as sections in the HTML. They are basically the same in function, but it is nice to have some distinction between the two.

Page controllers are loaded for each route that is matched and the template for that route is bound to it. If one has not been defined a plain object will be assigned as the page's controller.

Item controllers are instantiated for each item in a bind-repeat list and those elements are bound to the item controller. Each controller instance has the model and the element set on it.

Both types of controllers provide data for the views that are bound to them. They also provide actions that the views can call on events such as on a button click or form submit. Controllers can trigger model loading, updates, and saving. They put model objects on themselves as properties that the view can bind to. For example, an account page controller may load the current user's information and store that user on itself like this.user = loadedUserData. Then the view can bind to is with user.name etc.

An example controller might look like this:

Controller.define('userAccount', function(controller) {

  User.loadMe(function(err, user) {
    controller.user = user
    controller.sync()
  })

  controller.saveUser = function() {
    controller.errors = null
    var errors = controller.user.validate()
    if (errors) {
      controller.errors = errors
    } else {
      controller.processing = true
      controller.sync()

      controller.user.save(function(err, user) {
        controller.processing = false
        if (err) {
          controller.errors = [ err ]
        } else {
          controller.user = user
        }
        controller.sync()
      })
    }
  }
})

You'll notice there are several calls to controller.sync(). This is required to make the HTML update after data changes. Some frameworks try to hide this necessary step by wrapping every asynchronous method with their own (e.g. Angular's $timeout) but rather than trying to hide it we eliminate a ton of complexity and custom framework knowledge by letting you do this explicitly. The result is a smaller framework, less to learn, and fewer frustrations. It's all about tradeoffs, and we liked the tradeoff of calling controller.sync() much better than complicating the framework or writing boilerplate jQuery updates whenever a property changes.

Views

The views are straight up HTML. This HTML is bound to it's controller. Attributes in the HTML signal bind-points and allow for the HTML to be updated when the controller or model is changed. New binding types can be created easily, allowing for app-specific extensions to your application.

Some examples of binding types are:

  • bind-repeat which copies the element for each item in the array it references
  • bind-if allows showing the element if the expression in the attribute is true or hides it if false
  • attr-src will change the src attribute of an image as the model changes (e.g. attr-src="user.avatarUrl")

These bindings are very similar to Angular.js directives and many work the same as Angular's equivalent. For a complete list with documentation see the API (coming soon).

A function that returns a valid jQuery element is what is needed to register a template. Templates can be stored in the page or provided as strings with your build-system. The following shows how you would retrieve a template within a script element using the name attribute. Note: Chip will do this automatically, looking for scripts with the attribute type="text/html" and adding them, but you can manually do this another way.

chip.template.userAccount = $('script[type="text/html"][name="userAccount"]').html()
Clone this wiki locally