.js

A Non-Frameworky Framework



Luke Karrys

Ampersand Ampersand
Ampersand Ampersand

What is Ampersand?

Backbone-esque

÷

Node style modules

+

Advanced features

Ampersand

No monolithic core

npm install
ampersand-view
ampersand-state
ampersand-collection
ampersand-subcollection
ampersand-router
ampersand-model
ampersand-view-switcher
ampersand-version
ampersand-sync
ampersand-form-view
...

Node Style

Everything is on

Small, focused modules

Semver + quick releases

npm test browserify test/* | tape-run

npm start run-browser test/index.js

Built for the browser

Flexible!??

When you say flexible, I hear footguns.
Anyone who has been burned by "flexible" tools

Offset by:

Well defined approaches
Maximized simplicity

Composable


└─┬ ampersand-model@4.0.3
  ├── ampersand-state@4.3.14
  ├── ampersand-sync@2.0.4
  └── ampersand-version@1.0.1
    

└─┬ ampersand-rest-collection@2.0.3
  ├── ampersand-collection@1.3.17
  ├── ampersand-collection-rest-mixin@3.0.0
  └── ampersand-collection-underscore-mixin@1.0.2
    

└─┬ ampersand-view@7.1.4
  ├── ampersand-collection-view@1.1.2
  ├── ampersand-dom-bindings@3.3.1
  └── ampersand-state@4.3.14 # !!!
    

└─┬ ampersand-YOUR-MODULE-OR-MIXIN@1.0.0
  ├── react@???
  ├── some-new-crazy-stuff-no-one-has-ever-heard-of@???
  └── ampersand-state@4.3.14
    

State


var Person = State.extend({
    props: {
        name: 'string'
    },
    session: {
        type: {
            type: 'string',
            default: 'JS'
        }
    },
    derived: {
        title: {
            deps: ['name', 'type'],
            fn: function () {
                return this.type + ': ' + this.name;
            }
        }
    }
});
var person = new Person();
person.on('change:title', console.log.bind(console));
person.name = 'Luke Karrys'; // "JS: Luke Karrys"
person.type = 'Ampersand'; // "Ampersand: Luke Karrys"
    

Nested State


var Project = State.extend({
    children: {
        assignee: Person
    },
    props: {
        id: 'string',
        name: 'string'
    },
    derived: {
        title: {
            deps: ['assignee.title', 'name'],
            fn: function () {
                return this.name + ' / ' + this.assignee.title;
            }
        }
    }
});
var project = new Project({assignee: {name: 'Luke Karrys'}});
project.on('change:title', console.log.bind(console));
project.name = 'JSLA'; // "JSLA / JS: Luke Karrys"
project.assignee.type = '&.js'; // "JSLA / &.js: Luke Karrys"
    

Subcollections


var Projects = Collection.extend({model: Project});
var projects = new Projects(projectsData);

var ampersand = new SubCollection(projects, {
    filter: function (model) {
        return model.assignee.type === 'Ampersand';
    },
    watched: ['assignee.type']
});

console.log(ampersand.length); // 5
ampersand.at(0).assignee.type = 'JS';
console.log(ampersand.length); // 4
ampersand.at(0).assignee.type = 'JS';
console.log(ampersand.length); // 3
    

Stateful Views


var ProjectView = View.extend({
    template: '
  • ', bindings: { 'title': 'li' }, derived: { title: { deps: ['model.id', 'model.title'], fn: function () { return '(' + this.model.id + ') ' + this.model.title; } } } });

    Render Collection

    
    var AppView = View.extend({
        template: '
      ', render: function () { this.renderWithTemplate(); this.renderCollection(ampersand, ProjectView, '.ampersand'); return this; } }); new AppView({ el: document.querySelector('.container') }).render();

      Demo

      Source

      (Open the console)

      Get Involved

      Come hangout on Gitter

      Public Roadmap (with voting!)

      Our Triage Process

      Resources

      Tools

      Documentation

      Quickstart Guides

      Video tutorials

      Human Javascript Book

      Ampersand TodoMVC

      Thank you!

      @AmpersandJS
      @andyet

      @lukekarrys


      &you Newsletter