Backgrid.js

Backgrid.js is a set of components for building semantic and easily stylable data grid widgets.

It offers a simple, intuitive programming interface that makes easy things easy, but hard things possible when dealing with tabular data.

See Examples Download

Advantages

  • No Hungarian notations.
  • Solid foundation. Based on Backbone.js.
  • Semantic and easily stylable. Just style with plain CSS like you would a normal HTML table.
  • Low learning curve. Works with plain old Backbone models and collections. Easy things are easy, hards things possible.
  • Highly modular and customizable. Componenets are just simple Backbone View classes, customization is easy if you already know Backbone.
  • Lightweight. Extra features are separated into extensions, which keeps the bloat away.
  • Good documentation.
  • Well tested. Comes with 100s of test cases.

Supported browsers: [1]

  • Internet Explorer 8+
  • Chrome 4+
  • Safari 4+
  • Firefox 4+
  • Opera 9+

Backgrid.js depends on 3 libraries to function:

Something like the following will get the Backgrid.js core loaded:

Adjust the paths as needed.

Collection and Model

Before you can display any tabular data in a grid, you must first obtain the data.

At the most basic level, Backgrid pretends that every row is a model object and the whole table is backed by a simple Backbone collection.

Suppose we have a list of territory info objects:

Grid

The main entry point of the Backgrid package is the Backgrid.Grid class. You can create a default Backgrid by first defining some columns, and then put that list of columns and the collection of data into the Grid constructor like this:

Result


The list of column definitions Backgrid.Grid expects is simply a list of JSON objects, which you can hardcode into your HTML templates or retrieve from a server when the DOM is ready. Backgrid.js doesn't care where the column definitions come from, as long as you supply the list to the Grid constructor.

As expected, you now have a basic editable data grid displayed. All the columns headers are labeled and sortable by default. ID cells are not editable, and all other cell types have reasonable validation built in. If the table gets too large, you get a scroll bar.

Backgrid.js comes with 10 basic cell types in the core and many others as extensions. Cell types such as Select2Cell and MomentCell give you a much richer editing interface for option lists and datetime values on desktop browsers. In addition, there's a wide range of possibilities with how the data is converted for display and persistence by using formatters or customizing cell classes.

Paginator

If you have a large result set like the above, you'd probably want to paginate your results. This is easily achieved in Backgrid.js.

Backgrid.js comes with a paginator extension which you can load by including the following into your head tag:

To use the paginator, you must first declare your collections to be a Backbone.PageableCollection, which is a simple subclass of the Backbone.js Collection with added pagination behavior.

Result

How to Use the Grid

As described in the examples above, a basic grid needs only a collection and a list of column definitions.

Manipulating Columns and Rows

It is very easy to insert or remove a row in a grid, you just have to pass a model reference to Grid#insertRow or Grid#removeRow.

Inserting and remove columns is similarly easy. You just need to pass some definitions to Grid#insertColumn or Grid#removeColumn.

Customization

The various ways of customizing a grid are described in the following sections.

Column Defaults

Column defaults and required parameters are defined in the Backgrid.Column#initialize method.

Column Definition

A Column is a placeholder for a column definition.

You usually don't need to create an instance of this class yourself, as a collection of column instances will be created for you from a list of column object literals you provide to the Backgrid.js view class constructors.

Internally, columns are stored as a collection in the form of Backgrid.Columns. In addition, all parent views will convert the column definition into a Backgrid.Columns collection and pass a reference to any subviews that require it.

Listening to Column Attribute Changes

Occasionally, you may want to listen to column attribute change events. In that case, you can choose to initialize a Backgrid.Columns collection and listen to events from the individual models.

Demo

Try them

Name (StringCell) Age (IntegerCell) Birthday (DateCell) Gender (SelectCell) Alive (BooleanCell)
URL (UriCell) Email (EmailCell) Next Delivery Time (DateTimeCell) His Local Time (TimeCell) Change in Wallet (NumberCell)

Configuring Cells

While many built-in cells provide reasonable defaults, you may choose to configure them to suit your own needs.

Cell types that you are most likely to configure are the NumberCell, DatetimeCell and SelectCell classes. Once configured, you may use them as the cell attribute values in column definitions.

Pro Tip

SelectCell treats all option values as strings by default, if you need to persist a different type of values into your model, you should extend SelectCell to provide your own formatter.

See the JSDoc for the various Cell classes for details on what you can configure using this method.

Custom Cell

If the built-in and extension cell classes are not enough for you, you may choose to create your own cell class and supply it to a column definition.

If your custom cell will still use a <input type="text" /> like the predefined ones for editing, you may choose to subclass Cell or one of the predefined classes and simply define a className and a formatter. In fact, most of the core cell classes are done this way.

If your cell class will render differently in display mode, you may simply override Cell#render() in your subclass.

Custom CellEditor

Advanced Usage

Some cell types, like the TextCell extension, may only make sense if the editor is rendered in a modal dialog or a form element in a different part of the page. In that case the default InputCellEditor, which renders a <input type="text" />, will not be suitable and a new CellEditor must be defined.

A custom cell editor should subclass CellEditor as it defines a number of required parameters in its initializer and clean up operations that are necessary for most cell editors. When a cell class enters edit mode, a new editor instance is constructed by given it the required parameters, and then a Backbone event edit is fired from the cell instance itself. A custom cell class can act on this event to do anything before the cell editor is rendered.

Once the cell has entered edit mode, a Backbone event editing is fired. A custom cell class can then act on it to do anything after the cell editor has been rendered, e.g. placing the focus inside the editor.

During editing, if an error is encountered (see the formatter protocol below), a cell editor should fire a Backbone event error so that listeners—usually a cell instance—can respond appropriately. When editing is done, a cell editor should fire a Backbone done event. A cell should be listening to this event so it can remove its editor and re-render itsef in display mode.

Truely Advanced Hacking

At the most basic level, Cells and CellEditors are simply Backbone.View classes that are guaranteed to be given a number of parameters when constructed by Row. You can use any Backbone.View as your Cell and CellEditor.

Custom Formatters

In Backgrid.js, cell formatters serves the purpose of converting values between JSON value types and strings, and validation. Writing formatters for value conversion and validation is easy as you only have to conform to a very simple protocol.

Any formatters must have the following two methods defined:

fromRaw() is called by Backgrid.Cell and its subclasses whenever a raw model value needs to be formatted into a humanized form for display.

toRaw() is called by Backgrid.CellEditor and its subclasses whenever a user input string needs to be converted back to a raw JSON value for model persistence.

Validation

In addition to user input conversion, toRaw() also validates the user input during conversion. If the user input is invalid or cannot be converted to a JSON value, toRaw() MUST return undefined instead of throwing an Error.

In addition to using formatters to do simple yes or no validations, if your model class has a validate() method defined, it will also be used for validation after trying with the formatter.

Using Custom Formatters

A custom formatter can be used instead of the cell's default by extending the cell:

Understanding the Default Header

Backgrid.js comes with a default header section, a header row and a header cell implementation that renders a sorter if the column is sortable. The text inside the header cells comes from the column definitions. If a label is not defined in a column definition, its name is used as the label instead.

The default header cell implementation supports sorting in ascending or descending order, using the column's natural ordering. The sorter will also allow cycling back to the table's default sorting order, which is sorting by the model server IDs and client IDs.

Customizing the Header

Advanced Usage

You are allow to use a different header cell class on columns. There is no restriction on what a header cell must do. In fact, any Backbone.View class can be used. However, if you wish to modify how the sorter behaves, you must implement the sorting protocol. See the JSDoc for details.

Customizing Row

A row is simply an intermediary view class that constructs the appropriate Cell class instances for rendering the model columns.

If you would like to override how a row is rendered, you may define your own Row subclass and give it to a Body described below.

Using a Custom Row

Advanced Usage

If you have a custom Row class that you would like to use in place of the default Row, you may supply it to the Body constructor as follows:

Customizing Body

Advanced Usage

Body is the intermediary view that coordinates between the various parts of the grid. Specifically, the default implementation is responsible for re-rendering the rows when any model is inserted into, removed from, or reordered in the underlying collection. See the JSDoc for details.

Putting Things at The End of a Table

The default Footer class is an abstract class that only defines a number of required constructor parameters. If you wish to append additional information to the end of a table you must subclass Footer and supply the class to the Grid constructor.

Very often, you'll want to append a paginator to the end of your table if there are too many rows. For this, there's already a paginator extension provided for you.

Paginator

Best Used On

  • Desktop
  • Mobile

When to Use

When you have more data than your grid can fit, you can use Paginator to break the display of your data into pages.

Prerequisites

Backgrid.Extension.Paginator needs a Backbone.Collection subclass that supports pagination. Luckily, there is already one available specially written for this purpose - Backbone.PageableCollection.

Backbone.PageableCollection is a strict superset of the vanilla Backbone.Collection with additional pagination and sorting functionality. If you like, you can use Backbone.PageableCollection throughout your application and it will work exactly the same as Backbone.Collection.

Backbone.PageableCollection

Out of the box, Backbone.PageableCollection works with RESTful APIs that accept Ruby's will_paginate pagination query parameters but you are able to configure the query string mapping anyway you like. The following example works with Github's API:

Configuring Backgrid.Extention.Paginator

Backgrid.Extension.Paginator supports a few configuration options to adjust to the size of the result set.

Result

TextCell

Best Used On

  • Desktop
  • Mobile

When to Use

TextCell is a string cell type that renders a form with a text area in a modal dialog instead of an <input type="text" /> editor. It is best suited for entering a large body of text.

Prerequisites

TextCell require bootstrap-modal.js to render it's modal dialog.

Result

MomentCell

Best Used On

  • Desktop
  • Mobile

When to Use

While the core DatetimeCell is light-weight and does the job of formatting IS0-8601 datetime strings fairly well, it may not be well suited when the datatime strings are not in ISO format.

Prerequisites

MomentCell uses Moment.js to render a very powerful datetime cell.

Usage

The default MomentCell acts just like DatetimeCell, so if you have a column with datetime values, the default MomentCell is almost a drop-in replacement, with the only difference being that an offset is always present in the output.

In addition to the ability to read and write ISO-8601 datetime strings. By specifying the model and display formats, MomentCell can convert and validated any datetime values moment.js understands.

Like the core cell types, you can configure MomentCell simply by extending it.

Result

When to Use

When you have a relatively large number of available options for a column, or want to use a select box with autocomplete capability.

Prerequisites

Select2Cell uses the Select2 jQuery plugin to render its select box.

Usage

Select2Cell is a very simple extension of the default SelectCell. You can configure individual instances by supplying a select2Options object hash during extension, in addition to the options SelectCell supports.

Result

LatLngCell

Coming soon...

Out of the box, Backgrid.js generates simple semantic HTML table elements that you can style with pure CSS. This section is only going to briefly describe some of the more important classes, and things that you should be aware of when styling.

.backgrid-container

This is the class that you should put into any container element that will hold the generated table. By default, it has a fixed maximum height and 100% width with no borders and paddings. It also serves as a positioned element so if you need to absolutely position any elements inside your custom table element classes, you can position them against this container.

 

.backgrid

This is the class that will be applied to every Backgrid.js generated table. All other Backgrid.js default styles on table elements will only apply to descendents of tables of this class.

 

Although usually unnecessary, if you want to completely remove all Backgrid.js styles, you can supply a className attribute to the Backgrid.Grid constructor:

.backgrid .*-cell

Every cell class Backgrid.js defines has a CSS class applied to them of the same, but dasherized name. The default styles apply a text-align: left to text cells and text-align: right to numeric and datetime cells. All cell editor that uses the <input> element is absolutely positioned against the table cell.

See the relevant cell classes for details.

How do I validate user input?

See Formatter.

Why doesn't Backgrid.js support AMD (or NPM)?

The same question can be asked for volo, bower, ender, browserify and many other competing solutions. The number one reason Backgrid.js does not support AMD is because of the barrier it presents to writing extensions that require third-party libraries that don't support AMD. In addition to this, Underscore.js and Backbone.js also do not support AMD at this time.

The problem with supporting any package manager is that Backgrid.js is a highly modular project, and that deciding to use any package manager presupposes all its submodules and dependency is compatible with such a package manager and its importing mechanism. The Javascript ecosystem has gotten so diverse now that there is still not yet a clear packaging winner that everybody uses and works well under most situations, it is also not clear that ES Harmony's module system will be backward compatible with AMD.

Having said that, Backgrid.js doesn't do anything to prevent you from adding support to your favorite package manager. You are encouraged to fork and maintain your own Backgrid.js packages.

You are also more than welcomed to convince me on Github as you may probably know more than I do about packaging Javascripts.

Where do I go to ask questions?

Ask on the Google Group mailing list or go to Stackoverflow with the tag backgrid where either I or fellow users can help you.

Does Backgrid.js support adaptive scrolling?

Some data grid widgets out there support a technique called adaptive scrolling, meaning the DOM elements will be swapped out of a viewport and new ones appended as the models are loaded from the server, thus keeping the memory more or less constant while providing an illusion to end-users that there's no limit to the number of rows the data grid can handle.

Backgrid.js has something better and achieves the same effect with much cleaner code - paginator extension, which uses backbone-pageable. The paginator supports both paging on the server-side, or preloading all the models and paging purely through the browser. Paginated Backgrid.Grid instances only render one page of DOM nodes at a time to save memory and keep your web page responsive.

Does Backgrid.js support function aggregates?

No, because it is not the goal of this project to produce a full-fledged web-based spreadsheet. However, doing aggregation is trivial using Underscore.js methods

Does Backgrid.js support multi-user editing?

Again, it is out of the scope of this project as this functionality requires a broker to arbitrage between users and is mostly found in web-based online spreadsheet products.

Does Backgrid.js support feature (X)?

If the feature you have in mind isn't found here in this Backgrid.js version, it could either be in the works or under consideration.

See the list of tasks and enhancements.

How to build Backgrid.js?

See Building.

How do I contribute?

See Contributing.

Changelog

0.1
Initial Release

Copyright © 2013 Jimmy Yuen Ho Wong and Contributors.

Backgrid.js Javascript and CSS source code licensed under the MIT license.

Documentation licensed under GPLv3.