Book Image

Getting Started with Twitter Flight

By : Tom Hamshere
Book Image

Getting Started with Twitter Flight

By: Tom Hamshere

Overview of this book

<p>Flight is a lightweight, component-based JavaScript application framework developed by Twitter for Twitter.com. It is an exciting alternative to the complexities of modern MVVM frameworks, offering a minimal API that allows you to write fast, reliable, scalable applications with a minimum of boilerplate code.</p> <p>Getting Started with Twitter Flight offers the reader insight into why Flight was created and how to use it to build performant, powerful web apps from a unique perspective – that of someone who has had the opportunity to work directly with the team that created it. From a basic knowledge of JavaScript and jQuery, you will explore every aspect of Flight through practical examples and detailed explanations.</p> <p>Learn what separates Flight from other frameworks, why Flight was created, and why you should use it in your next project. Discover the power of Flight’s component-based architecture and use mixins, an exciting alternative to class-based inheritance, to create templating systems and data storage layers.</p> <p>Getting Started with Twitter Flight provides all you need to know to build everything from UI widgets to large-scale, data-driven applications.</p>
Table of Contents (22 chapters)
Getting Started with Twitter Flight
Credits
Foreword
About the Author
About the Reviewers
www.PacktPub.com
Preface
Index

Components


There are three aspects to the component API: component and mixin definition, component instantiation, and base component methods. The base component methods are available as first-class citizens from within component and mixins definitions.

Component definition

Components are AMD modules and should return a defined component. This is an example component file:

// AMD module definition
define(function () {
  // require defineComponent
  var defineComponent = require('flight/lib/component');
  // export defined component
  return defineComponent(myComponent);
  // component definition
  function myComponent () {
    // internal methods
    this.foo = function () {
      // do something
    };
  };
});

Mixin definition

Mixins are AMD modules exactly like components, only they return a component definition, rather than a defined component, so don't require defineComponent:

// AMD module definition
define(function () {
  return myMixin;
  // mixin definition
  function myMixin () {
    // internal methods
    this.bar = function () {
      // do something
    };
  };
});

Using mixins

Mixins can be mixed into components, as shown in the following code:

// AMD module definition
define(function () {
  // require defineComponent
  var defineComponent = require('flight/lib/component');
  // require mixins
  var myMixin = require('component/my_mixin');
  // export defined component, adding mixins
  return defineComponent(myComponent, myMixin);
  // component definition
  function myComponent () {
    // internal methods
    this.foo = function () {
      // components have access to mixin methods
      // as first-class citizens
      this.bar();
    };
  };
});

Mixins can also be mixed into other mixins using compose.mixin within the mixin definition. For example, look at the following code:

// AMD module definition
define(function () {
  // require Compose
  var compose = require('flight/lib/compose');
  // require another mixin
  var someOtherMixin = require('component/some_other_mixin');
  
  return myMixin;
  // mixin definition
  function myMixin () {
    compose.mixin(this, [someOtherMixin]);
    // internal methods
    this.bar = function () {
      // do something
    };
  };
});

Instantiating components

The following code example shows a component (component/my_component.js) being required and then instantiated in three different ways:

// require component constructor
var MyComponent = require('component/my_component');
// attach component instance to an HTMLElement
MyComponent.attachTo(document);
// attach component instance to all elements matching a css selector
MyComponent.attachTo('.modal');
// attach component instance to a jQuery object
var $div = $('<div />');
MyComponent.attachTo($div);
// pass options to component instance
MyComponent.attachTo($div, {
  defaultText: 'Hello, World!'
});

Methods available on a component instance

The defineComponent method mixes in Flight's core functionality into a component definition. The methods in this section are available to any component within the function definition.

Component methods can be broken up into five sections: Advice, Attributes, DOM selection, Events, and Teardown.

Advice

Advice allows component and mixin methods to be extended or overridden without clobbering the original method using before, after, and around. Advice is also used to initialize a component.

before

Execute a method before the named method is executed:

this.before(methodName, callback);
after

Execute a method after the named method is executed:

this.after(methodName, callback);
around

Execute a method before the named method is executed, and optionally call the named method:

this.around(methodName, function (originalMethod) {
  // maybe call
originalMethod();
});
Initialization

Use after to initialize a component.

// component definition
function myComponent () {
  this.after('initialize', function () {
    // do initialization
    // this will be called when a component is
// attached to a DOM node
  });
}

defaultAttrs

Default attributes can be used to configure a component or mixin:

// component definition
function myComponent () {
this.defaultAttrs({
defaultText: "Hello, handsome!"
});
});

Default attributes can be overridden when instantiating a component:

var MyComponent = require('component/my_component');
MyComponent.attachTo(document, {
  defaultText: "Hello, World!"
});

select

Use a selector defined in defaultAttrs to gain a reference to a jQuery collection containing elements within the component that match the selector:

this.defaultAttrs({
  listItemSelector: '.list-item'
});
this.getListItems = function () {
var $listItems = this.select(attrKey);
return $listItems;
};

Events

Flight components should attach event listeners and trigger events through Flight's event methods:

on

Attach an event listener to the component root:

this.on([selector], eventName, callback);

In the this example, an event listener is attached to the component's root node:

this.handleTaskData = function (event, data) {
  // do something
};
this.after('initialize', function () {
this.on('dataTask', this.handleTaskData);
});

To attach an event listener to a specific element, a CSS selector, DOM element, or jQuery collection can be passed as the first argument to on, as seen in the following examples:

this.on('.list-item', 'click', this.handleListItemClick);
this.on($('.list-item'), 'click', this.handleListItemClick);
this.on(document, 'dataTask', this.handleTaskData);

To handle dynamic creation of elements, use the following syntax to provide event delegation. attributeKey needs to be defined in defaultAttrs.

this.on(eventName, {
  attributeKey: callback
});

In this example, handleListItemClick will be called when the user clicks on an element matching .list-item.

this.defaultAttrs({
  listItemSelector: '.list-item'
});
this.handleListItemClick = function (event) {
  // do something
});
this.after('initialize', function () {
this.on('click' {
    listItemSelector: this.handleListItemClick
});
});
off

Remove an event listener:

this.off([selector, ] eventName [, callback]);

In this example, all listeners listening for dataTask events will be removed.

this.off('dataTask');
trigger

Trigger an event:

this.trigger([selector, ] eventName [, data]);

This example shows a dataTask event being triggered on the component's root node with a data payload.

this.trigger('dataTask', {
  description: 'Make tea'
});

teardown

teardown() destroys the component instance and removes all event handlers declared with this.on.

this.teardown();