Code Monkey home page Code Monkey logo

end-dash's Introduction

Getting Started

EndDash is a two-way binding javascript templating framework built on top of semantic HTML

In its current release, EndDash relies on Backbone objects. See the dependency section for further details.

(Documentation is below)

Setting up

Install EndDash and install grunt helper

npm install

# We use grunt for running tasks.
npm install -g grunt-cli

# Build end-dash in build/ directory
grunt build # also aliased as `grunt`

Include the library and dependencies.

<!-- Make sure you include these libraries before EndDash -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://underscorejs.org/underscore.js"></script>
<script src="http://backbonejs.org/backbone.js"></script>

<script src="/end-dash/build/end-dash.js"></script>

Define your templates.

<script type="text/enddash" name="character">
  <div class="user">
    <p>
      Hello, my name is <span class="firstName-"></span>
      <span class="lastName-"></span>...
    </p>

    <strong class="quip-"></strong>
  </div>
</script>

WARNING: A template can only have one root element. In the above case, it is the div with class 'user'.

Load your templates into EndDash.

$.ready(function() {
  // Load all the templates on the page.
  EndDash.bootstrap();
)};

Bind your templates to models in your application code.

  var tony = new Backbone.Model({
    firstName: 'Tony',
    lastName: 'Stark',
    quip: "You know, the question I get asked most often is, 'Tony, how do you go to the bathroom in your suit?'"
  });

  var template = EndDash.getTemplate('character', tony);

  $('#content').html(template.el);
});

If your models changes, the DOM will update to reflect the changes.

Ready Made Examples

If you clone this repo and install grunt as described above you can play with some end-dash examples in your browser. Just type grunt in the root directory to build the current version of end-dash into the build directory, and then open up any of the example html files in the examples directory in your browser (open examples/looping.html for example works on OS X), and you can edit the templates or models directly in the html file if you want to experiment.

Documentation

Using Model Attributes

Inputs

Looping

Conditionals

Scoping

View Integration

Templates

Partials

Debugging

Dependencies

Contributing and Future Improvements

Using Model Attributes

Variables

EndDash variables are rendered into the body of HTML elements, displaying their values as ordinary text:

<div class="user-">
  My name is <span class="firstName-"></span> <span class="lastName-"></span>.
</div>

Attibute Interpolation

Model properties can also be interpolated into any html tag attribute.

<a href="/person/#{firstName}"> Home Page </a>
template.bind(new Backbone.Model({firstName: 'Derrick'}));

Resulting Tag:

<a href="/person/Derrick"> Home Page </a>

Inputs

EndDash does two-way binding between model attributes and input elements.

Text Inputs

Text inputs are bound to a referenced attribute on the model in scope. To create this binding, add the attribute name with a dash at the end as a classname in the template.

<p>
  What is your name?
  <input  type="text" class="name-">
</p>

Radio buttons

Radio buttons bind the selected button's value to the model's referenced attribute.

<div>
  <p>Who is your favorite character?</p>
  <input type="radio" class="name-" name="name-" value="tony" id="tony"/>
  <label for="tony">Tony</label>
  <input type="radio" class="name-" name="name-" value="pepper" id="pepper"/>
  <label for="pepper">Pepper</label>
  <input type="radio" class="name-" name="name-" value="james" id="james"/>
  <label for="james">James</label>
</div>

Checkboxes

Checkboxes are trickier. When unchecked, the referenced attribute on the model will be 'false'. When checked, the referenced model's attribute will be set to the attribute value on the input element (or 'true' if no value is defined).

<p>Do you want to receive notifications about Iron Man?</p>
<input type="checkbox" name="notifyList" class="notify-" />

Looping

Simple Looping

To reuse a set of DOM elements for each child model in a collection, add the data-each attribute to the parent of this set.

  <div data-each>
    <div class="firstName-"></div>
  </div>

The object in scope at these elements, will be iterated through (using .each). Each child of this collection will be bound to the nested elements.

Given the above template and the collection:

var characters = new Backbone.Collection([
  new Backbone.Model({firstName: 'Tony'}),
  new Backbone.Model({firstName: 'Pepper'}),
  new Backbone.Model({firstName: 'Iron'}),
  new Backbone.Model({firstName: 'James'})
]);

the output will be:

  <div data-each>
    <div class="firstName-">Tony</div>
    <div class="firstName-">Pepper</div>
    <div class="firstName-">Iron</div>
    <div class="firstName-">James</div>
  </div>

Note that the elements iterated over must have one root. (Here <div class="firstName-"></div>).

Polymorphic attributes

If your objects have an enum field, you can branch based on its value.

For example, role behaves as a polymorphic attribute:

<div class="rolePolymorphic-" data-each>
  <div class="whenHero-">
    <span class="firstName-"></span> says:
    Don't worry. I'll probably save you.
  </div>

  <div class="whenVillain-">
    <span class="firstName-"></span> says:
    Worry.
  </div>

  <div class="whenCivilian-">
    <span class="firstName-"></span> says:
    Get me outta here!
  </div>
</div>

Given the following objects:

new Backbone.Collection([
  new Backbone.Model({firstName: 'Tony', role: 'hero'}),
  new Backbone.Model({firstName: 'Pepper', role: 'civilian'}),
  new Backbone.Model({firstName: 'Aldrich', role: 'villain'}),
  new Backbone.Model({firstName: 'James', role: 'hero'})
]);

The template would produce the following HTML:

<div class="rolePolymorphic-" data-each>
  <div class="whenHero-">
    <span class="firstName-">Tony</span> says:
    Don't worry.  I'll probably save you.
  </div>

  <div class="whenCivilian-">
    <span class="firstName-">Pepper</span> says:
    Get me outta here!
  </div>

  <div class="whenVillain-">
    <span class="firstName-">Aldrich</span> says:
    The whole world's gonna be watching.
  </div>

  <div class="whenHero-">
    <span class="firstName-">James</span> says:
    Don't worry.  I'll save you!
  </div>
</div>

To add a default case, include a non-EndDash child div:

<div class="rolePolymorphic-">
  <div class="whenHero-">
    <span class="firstName-"></span> says:
    Don't worry.  I'll probably save you.
  </div>

  <!-- Default case! The following gets rendered unless
       model.get('role') === 'hero'. -->
  <div>
    <span class="firstName-"></span> says:
    I've lost my memory.  I don't know who I am!
  </div>
</div>

Collection Attributes

Please note: Backbone.Collection does not support attributes natively for its collections, but there are a number of options for extending collections to do so. EndDash supports collection attributes as long as they are implemented according to Backbone.Model API, via the get method (which Backbone.Collection natively uses only for getting a model by id, not an attribute by name). Typically collection attributes are used for metadata about the collection, such as total size (if the collection is paginated and this is different than length), as in the example below:

<div class="authorizedPeople-" >
  <p>
    There are <span class="totalCount-"></span> people allowed in Tony's basement.
  </p>
</div>

Conditionals

A ternary operator is available for presence handling via 'truthiness' for attributes that may be present, with or without a false condition:

<div class="user- #{availability ? available : unavailable}">
  <p>
    My schedule is very full. <span class="isAvailable-">I just have a few openings</span>
  </p>
</div>

The same truthiness controls conditional visibility EndDash class elements that start with is or has, and their boolean opposites isNot and hasNot, as above with isAvailable-. EndDash will hide (via a display:none style attribute) any such element when its named attribute is falsy (or hide when truthy in the case of isNot and hasNot.)

template.bind({
  user: new Backbone.Model({
    firstName: 'Tony',
    lastName: 'Stark',
    alias: 'IronMan'
    availability: ['10am', '2pm']
  });
});

Scoping

What is Scoping?

Scope in EndDash refers to the model on the top of the EndDash stack. Each template and partial is given its own scope. The 'root' scope is always the object passed to EndDash's 'bind' or 'getTemplate' function.

template.bind({
  user: new Backbone.Model({
    firstName: 'Tony',
    lastName: 'Stark',
    hobby: {
      description: 'Building all the cool technology'
    }
  })
});

The root object is the object literal with the property 'user'.

Scope can change in two ways:

Scoping Down With A Dash

<div class="user-">
  //Internal HTML
</div>

Scopes into the Backbone Model with properties: 'firstName', 'lastName', and 'hobby'. This syntax only allows scopping down.

Scoping With Paths

(UNIX style)

<div class="user-">
  <div data-scope="/">
    //Iternal HTML
  </div>
</div>

Scopes down into the user object and then, via the data-scope property, scopes back to the root object (the object literal with propery 'user').

Normal UNIX path shorthands apply: .. to move back up a scope level, / to seperate scope levels, . for the current scope.

<div class="user-">
  //User scope
  <div class="hobby-">
  //Hobby scope
    <div data-scope="../">
    //Back in User Scope
      <div data-scope="/user/hobby">
      //Back in Hobby scope
      </div>
    </div>
  </div>
</div>

class="user-" is actually syntactic sugar for data-scope="./user". Using data-scope like this, at the current scope, is mainly useful for accessing a property of a nested model in the same DOM element that you change the scope.

View Integration

EndDash provides dynamic behavior often otherwise handled by views in Backbone. If more specific dynamic behavior is required, take advantadge of EndDash's hooks to Backbone Views. Simply add the html attribute data-view with the value of your viewName, to the template.

<div>
  <h2>
    Configure Iron Man's suit below:
  </h2>
  <div class="suit-" data-view="iron_man_suit_view">
    <div id="suitConfig">
  </div>
</div>

When EndDash runs into a data-view, it will lookup the view and initialize it with the model in scope at the DOM element where the view is initialized.

To lookup the view, EndDash uses a simple view store. You can register views by calling EndDash.registerView with the view name and the view class object. You can also define your own function and pass it into EndDash.setCustomGetView

EndDash.registerView('myViewName', viewObj);
var views = {},
    getViews = function(name) {
      return views[name];
};
EndDash.setCustomGetView(getViews);

Templates

Registering a Template

This can be done manually.

EndDash.registerTemplate('greetings','<div>Hello Citizens, I am <span class="name-"></span></div>');

Or, via EndDash.bootstrap.

To bootstrap, have your templates loaded as scripts of type 'enddash' on the page.

<script type="text/enddash" name="greetings">
  <div>
    Hello Citizens, I am <span class="name-"></span>
  </div>
</script>

Then call EndDash.bootstrap.

$.ready(function() {
  // Load all the templates on the page.
  EndDash.bootstrap();
)};

Binding to a Template

First, get the EndDash-parsed version of your template.

var template = EndDash.getTemplate('greetings');

Then bind it to a model.

var hero = new Backbone.Model({name: 'Superman'}),
    boundTemplate = template.bind(hero);

This can be done in a single step, by passing a model as a second argument to EndDash.getTemplate.

var hero = new Backbone.Model({name: 'Superman'}),
    boundTemplate = EndDash.getTemplate('greetings', hero);

Displaying HTML of a bound Template

Show the el property of the template.

$('.content').html(boundTemplate.el);

Partials

Small, reusable, components of HTML can be templated in EndDash as partials. To use a partial, add src="templateName" as an attribute to an element with no children.

<script type="text/enddash" name="superheroes">
  <img src="#{logo}" />
  <div class="heroes-">
    <div src="superhero-navigation" data-replace></div>
  </div>
</script>

The partial will be passed the model in scope as its root element.

The data-replace attribute tells EndDash to substitute the partial's root element for its partial. Without data-replace, EndDash will embed the root element beneath the partial's element and leave it.

If elsewhere you define this partial as:

<script type="text/enddash" name="superhero-navigation">
  <ul data-each>
    <li>
      <a href="#{url}"><span class="name-"></span></a>
    </li>
  </ul>
</script>

And bind to the top level template with:

template.bind({
    heroes: new Backbone.Collection([
      new Backbone.Model({name: 'Iron Man', url: '/superheroes/techGenius'}),
      new Backbone.Model({name: 'Spiderman', url: '/superheroes/webMaster'}),
      new Backbone.Model({name: 'Superwoman', url: '/superheroes/strong'})
    ]),
    logo: '/public/emblems/protectTheWorld'
});

This will result in:

<img class="/public/emblems/protectTheWorld">
<div class="heroes-">
  <ul>
    <li><a href="/superheroes/techGenius">Iron Man</a></li>
    <li><a href="/superheroes/webMaster">Spiderman</a></li>
    <li><a href="/superheroes/strong">Superwoman</a></li>
  </ul>
</div>

Debugging

Open up a debugger in development mode to inspect the context of the template.

Open a context in the highest template scope:

<body>
  <div debugger />
</body>

In a child model scope:

<body>
  <div class="questions-">
    <!-- Open a debugger in the scope of get('questions') -->
    <div debugger />
  </div>
</body>

Dependencies

In its current release, EndDash relies on Backbone style events to update the DOM when a bound object changes. This means only objects which define an interface with Backbone's "on, once, set, get" will interpolate model attributes into the DOM and update the DOM on model changes.

EndDash used without Backbone style getting & setting will still interpolate a bound object's attributes into the DOM but will not update the DOM on model changes.

Contributing and Future Improvements

There are a number of future improvements planned for EndDash and we'd love for you to be involved in them. Please Fork the EndDash repo and open pull requests or get involved in discussing features or improving documentation via GitHub issues or a PR on the README.md file. Our homepage at enddash.com is hosted on GitHub pages via the gh-pages branch, so feel free to improve and make PR's to the home page and live examples there as well.

Building and testing

To develop EndDash locally, you must have NPM and Grunt installed. From the directory of your local clone of the EndDash repository:

npm install

# We use grunt for running tasks.
npm install -g grunt-cli

# Build end-dash in build/ directory
grunt build # also aliased as `grunt`

# Run tests
grunt test

# Watch for changes and run tests
grunt watch

Future Improvements

Right now EndDash only supports browser side rendering, but we have plans to support Node.js server-side rendering as well, and hybrid rendering where templates are pre-processed server side and served as static compiled assets for the client. We also have a branch with a new interpolation syntax support to avoid requiring the use of span elements for dynamic text, and a few other ideas open or coming soon to GitHub issues and pull-requests on the github repo.

end-dash's People

Contributors

tobowers avatar pbadger avatar fredericoandrade avatar jameselkins avatar xcoderzach avatar chrisvoxland avatar

Watchers

mntz avatar James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.