linen

Linen (line-in) maps API's to bindable objects, and collections. At classdojo, we use linen to abstract our API from front-end, so we don't necessarily depend on any sort of API while developing new components. This allows us to rapidly build prototypes which can be wired up later.

Linen (line-in) maps API's to bindable objects, and collections. At classdojo, we use linen to abstract our API from front-end, so we don't necessarily depend on any sort of API while developing new components. This allows us to rapidly build prototypes which can be wired up later.

Here's an example person schema:

var linen = require("linen")();
 
linen.addSchema({
 
  // name of the schema - gets referenced by  
  // linen.model("person") 
  name: "person",
 
  //fields for the person. Keep in mind that model properties 
  //get *validated* against their coresponding field.  
  fields: {
    firstName: "string",
    lastName: "string",
 
    // virtual value - doesn't actually exist in the API 
    fullName: {
      $getfunction(model) {
        return model.get("first_name") + " " + model.get("last_name");
      },
      $setfunction(modelvalue) {
        var nameParts = String(value).split(" ")
        model.set("first_name", nameParts.shift());
        model.set("last_name", nameParts.join(" "));
      },
      $bind: ["first_name", "last_name"]
    },
 
    // fetches GET /people/:personId/friends when 
    // person.bind("friends").to(fn) is called 
    friends: [{
      $ref: "person",
      $fetchfunction(payloadnext) {
        transport.fetch(payload.method, "/people/" + payload.model.get("_id") + "/friends", next);
      }
    }]
  },
 
  //fetches GET /people/:personId when 
  //person.bind(property).to(fn) is valled 
  fetchfunction(payloadnext) {
    transport.fetch(payload.method, "/people/" + (payload.model.get("_id") || ""), next);
  }
});

To use the schema, simply call the following:

var person  = linen.model("person"),  //creates a new person 
existingPerson = linen.model("person", "someId"); //some ID 

Linen works by overriding the bind method to fetch from any API you have setup, so when you call:

 
//calls GET /people/someId 
existingPerson.bind("firstName").to(function(name) {
  console.log(name); 
}).now();

The existingPerson will asynchronously call .to(fn) when it's been loaded from the server. This is useful when data-binding to any sort of UI component, such as rivets.js, or paperclip.js.

Here's another example of data-binding to linen models:

 
// GET /people/someId/friends 
existingPerson.bind("friends").to(function(friends) {
 
  // GET /people/friendId 
  friends.at(0).bind("firstName").once().to(function(name) {
  }).now();
}).now();

The above examples make it easy to abstract models from any API. To demonstrate this, here's an example of using dummy data:

var existingPerson = new bindable.Object({
  firstName: "Ron",
  lastName: "Burgundy",
  friends: [
    new bindable.Object({
      firstName: "Brian",
      lastName: "Fontana"
    }),
    new bindable.Object({
      firstName: "Brick",
      lastName: "Tamland"
    }),
    new bindable.Object({
      firstName: "Champ",
      lastName: "Kind"
    })
  ]
});
 
 
existingPerson.bind("firstName").to(function(name) {
  console.log(name); //Ron  
}).now();
 
existingPerson.bind("friends").to(function(friends) {
  friends.at(0).bind("firstName").once().to(function(name) {
    console.log(name); //Brian 
  }).now();
}).now();

Returns a new linen instance

adds a new schema

Inspired by mongoose:

linen.addSchema({
  firstName: {
 
  }
});

returns a new, or existing model