Phalanx

is a Backbone wrapper library. Focusing to decouple view and manage ui component simply.

This project is maintained by ahomu

Getting started

Phalanx is a Backbone wrapper library. Focusing to decouple view and manage ui component simply.

Phalanx

via. Ancient Macedonian battle tactics - Wikipedia, the free encyclopedia

Basic view and component

This is UI component parts.

var LikeBtnComponent = Phalanx.Component.extend({
  // Events are delegated to the View.
  events: {
    'click .js-like': 'doLike'
  },
  // Elements with the data-ui are auto stored when create component instance.
  ui: {
    count: null
  },
  // Increment like count when POST completed.
  doLike: function() {
    $.post('/api/like', {id: this.id}, function() {
      this.$ui.count.text(parseInt(this.$ui.count, 10) + 1);
    }.bind(this));
  }
});

View that contains multiple components.

var ActivitiesListView = Phalanx.View.extend({
  // Specified name here, will specify as data-component attr in the HTML.
  components: {
    'likeBtn': LikeBtnComponent
  }
});

var listView = new ActivitiesListView({el: '#js-list'});

This is HTML.

<section id="js-list">
  <ul>
    <li>
      <a>screen_name</a>
      <p>Lorem ipsum dolor sit amet, consectetur adipisici…</p>

      <!-- Events that have been delegated to occur, creation of component is delayed. -->
      <div data-component="likeBtn">      
        <button class="js-like"><button>
        <span data-ui="count">3</span>
      </div>
    </li>
    ...
    ..
    .
  </ul>
</section>

Split the screen, Phalanx.View to manage a certain areas and Phalanx.Component to manage small specific function.

Declarative listening Component triggering events

Component triggered success event when $.get complete.

var ReadMoreBtnComponent = Phalanx.Component.extend({
  events: {
    'click [data-ui="btn"]': 'onClickBtn'
  },
  onClickBtn: function(evt) {
    var href  = evt.currentTarget.getAttribute('href');

    $.get(href, function(resp) {
      this.trigger('success', resp);
    }.bind(this));
  }
});

View is listening to success event from ReadMoreBtnComponent.

var ListView = Phalanx.View.extend({
  components: {
    'moreBtn': ReadMoreBtnComponent
  },
  listeners: {
    'success moreBtn': 'renderMore'
  },
  ui {
    list null
  }
  renderMore: function(html) {
    this.$ui.list.append(html);
  }
});

var listView = new ListView({el: '#js-list'});

This is HTML.

<section id="js-list">
  <div data-ui="list">
    <div>Item 1</div>
    <div>Item 2</div>
    <div>Item 3</div>
  </div>
  <p data-component="moreBtn">
    <a href="/api/path/to/list&page=2" data-ui="btn">Read more</a>
  </p>
</section>

Component plays a role in local without knowing of View. To receive the event, in conjunction with result of Component, View updates itself.

Layout regions and assignment Views

var RootLayout = Phalanx.Layout.extend({
  regions: {
    header : '#js-header',
    content: '#js-content',
    footer : '#js-footer'
  },
  onChange: function(regionName, newView, oldView) {
    // Called when regions view was changed.
  }
});

var rootLayout = new RootLayout({el: 'body'}),
    currentPage = '';

rootLayout.assign('header',  new HeaderView());
rootLayout.assign('content', new InitialView());
rootLayout.assign('footer',  new FooterView());

window.addEventListener('hashchange', function() {
  if (currentPage === location.hash.slice(1)) {
    return;
  }
  currentPage = location.hash.slice(1);

  // When a new View has been assigned, the old View is destroyed automatically.
  switch(currentPage)) {
    case '':
      layout.assign('content', new InitialView());
      break;
    case 'feed':
      layout.assign('content', new FeedView());
      break;
    case 'home':
      layout.assign('content', new HomeView());
      break;
    case 'inbox':
      layout.assign('content', new InboxView());
      break;
  }
});

This is HTML.

<body>
  <header id="js-header">
    <!-- HEADER -->
  </header>
  <div id="js-content">
    <!-- MAIN CONTENT -->
  </div>
  <footer id="js-footer">
    <!-- FOOTER -->
  </footer>
</body>

The layout manage the elements in the page, what View have been assigned. Have the role of like a controller.

Requirements

Depend Libraries

Document generator

Generating JavaScript API documents and introspection report.

npm install -g grunt-cli
npm install

grunt jsduck
grunt plato

Automated spec runner

Using mocha test framework with expect.js and sinon.js.

bower install
gem install juicer
./lib/sinon/build

brew install phantomjs
npm install -g testem

testem #run specs

TODO