Tuesday, 2 June 2015

A Backgrid Cell for displaying a link to a model's Url

When creating web applications that use Backbone I've found the Backgrid library useful for rapidly creating a user interface with a lot of functionality. With just a few lines of javascript you can display a table of data that allows sorting and in-row editing, and which updates a backing Backbone collection, thereby hooking directly into the infrastructure of the rest of your web page. And, like all good javascript frameworks, it:
  • has very few dependencies - just Backbone, Underscore (which Backbone requires anyway) and jQuery (which you will almost certainly be using anyway).
  • packs down nice and small - just 25KB.
  • is very extensible...
So I'd like to share a very simple extension that I've created, a Backgrid cell that will render a hyperlink to the model that it is displaying.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
    /* Cell which displays a link to the model's Url. View can be extended to set:
    *   title - title of the link
    *   target - frame that the link targets, defaults to '_self'
    */
    var ModelUri = Backgrid.UriCell.extend({
        render: function () {
            this.$el.empty();
            var rawValue = this.model.get(this.column.get("name"));
            var formattedValue = this.formatter.fromRaw(rawValue, this.model);
            this.$el.append($("<a>", {
                href: this.model.url(),
                title: this.title || formattedValue,
                target: this.target || '_self'
            }).text(formattedValue));
            this.delegateEvents();
            return this;
        }
    });

When using this cell the 'name' of the column definition should point at the model attribute that contains the link text. The column definition doesn't need to contain any information about where to load the link target from as it uses model.url() for that. If you look at the source of Backgrid itself you'll see that I've changed very little from the render method of the UriCell cell. A quick commentary on what the code does:
  • On line 8 this.column.get("name") retrieves the name of the attribute that contains the link text (the 'column' object is, itself, a model).
  • Also on line 8, this.model.get(...) retrieves the value for the link text from the bound model.
  • Line 9 uses standard Backgrid functionality to transform the raw value retrieved from the model using the cell's formatter. My cell uses the default formatter that simply returns the value that is passed to it, but if you wanted to extend ModelUri further to use a different formatter then you could.
  • Line 11 sets the link target to the value of model.url().
  • Line 13 allows the target frame to be specified, defaults to '_self'.
  • Line 14 sets the link text to the formatted value.
To use the cell you would need code that looked something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
 var UserCol = Backbone.Collection.extend({
  model: Backbone.Model,
  urlRoot: '/_users'
 });
 var grid = new Backgrid.Grid({
  selector: '#gridHolder',
  collectionClass: UserCol,
  comparator: 'reference',
  columns: [
   { name: "reference", editable: false, cell: ModelUri, label: "Filename" },
   { name: "processingState", editable: false, cell: 'string', label: "Status" }
  ]
 });

If you wanted the cell to render a link that would open the model url in a new tab/window then the 'target' property of the cell needs to be set to '_blank'. This can be achieved by further extending ModelUri; one way to do this is shown below:


1
2
3
4
5
6
7
8
9
 var grid = new Backgrid.Grid({
  selector: '#gridHolder',
  collectionClass: UserCol,
  comparator: 'reference',
  columns: [
   { name: "reference", editable: false, cell: ModelUri.extend({target: '_blank'}), label: "Filename" },
   { name: "processingState", editable: false, cell: 'string', label: "Status" }
  ]
 });


Hope you find this useful!

1 comment: