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.
Features
The goal of Backgrid.js is to produce a set of core Backbone UI elements that offer you all the basic displaying, sorting and editing functionalities you'd expect, and to create an elegant API that makes extending Backgrid.js with extra functionalities easy.
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+
Getting Started
Backgrid.js depends on 3 libraries to function:
Something like the following will get the Backgrid.js core loaded:
Adjust the paths as needed.
Examples
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
API Reference
Grid
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.
Columns
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.
Cell
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.
Formatter
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:
Header
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.
Row
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.
Body
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.
Footer
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.
Extensions
It is not necessary to create an extension project if you simply want to customize or extend some Backgrid.js classes for your own private use; however, if you have one or more Backgrid.js components that add new features to the core, you may consider packaging them up to share with the world.
A Backgrid.js extension is a directory structure that packages the necessary JS, CSS, tests, and document files.
To create an extension, clone the tree into your file system and type:
A new extension directory structure should have been created for
you under src/extensions
. The current implementation
of make extension
only creates a blank directory
filled with a number of blank files for you. You should take a
look at other extensions to copy what you need. e.g. Makefile,
.gitignore.
Extension Development Guide
The following is a guideline for extension development:
- There should be 1 .js file and 1 .css file. If your code base gets too large, consider breaking it into multiple extensions.
- There should be 1 .min.js file and 1 .min.css file produced for distribution.
- Your Makefile should emulate other extensions as closely
as possible. Specifically, you should have a
dist
rule that will take aDIST_DIR
variable from top-level make invocations and copy the output files to the destination directory. - You should use recess to lint your CSS file(s).
- You should follow the JS coding style defined here.
- Your .gitignore file inside the extension directory should ignore all output files.
- You should wrap your JS file in an immediately invoked anonymous function that lists out your dependencies in the parameter list.
- Your extension should live under
the
Backgrid.Extension
module. - You should clearly specify your dependencies in the README file if your extension relies on any libraries other than Backgrid.js and its dependencies.
- When in doubt, look at the other extensions for clues in organizing your code.
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
Select2Cell
Best Used On
- Desktop
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...Styling
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.
Frequently Asked Questions
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?
How do I contribute?
Changelog
- 0.1
- Initial Release
License
Copyright © 2013 Jimmy Yuen Ho Wong and Contributors.
Backgrid.js Javascript and CSS source code licensed under the MIT license.
Documentation licensed under GPLv3.