Friday, May 25, 2012

SitePen dgrid From Html and Footers

I'm still fairly new with using Javascript, so what I'm showing today is a way, but perhaps not the best way.

And that way is turn a simple HTML table into something nice using SitePen's dgrid, and adding a footer showing totals.

There are some basics you might want to be familiar with first, like Dojo (1.7.2 at the time of writing), using AMD, and perhaps using the SitePen dgrid.

I was doing a screen that has a whole bunch of HTML tables on it. And I thought that the Claro theme looked so nice, but the dojoTabular style was so out of place, that it would be nice to have the data styled like it was in a dgrid. Turns out, it wasn't as hard as I thought it might be. dgrid provides an awesome class that will convert the basics for a HTML table to a dgrid, called dgrid/GridFromHtml.

Since this was simple tabled data, and I didn't feel like creating a store for every table, I stored the data as a JSON value in a hidden form variable. In my Javascript, I would load that data, create the grid from the HTML, and use renderArray to populate the data.

Here's a small sample of what I did.

This is the HTML, though I've not bothered to populate the hidden element with actual JSON data. Just make it an array of entries, where each entry has columns that will match the column headers in the table.

My Table

Id Name Value

For your convenience, a simple function to convert the table to a grid.
function loadTable(dataId, id, options) {
    var data = dom.byId(dataId);
    if (data) {
        data = data.value;
        data = JSON.parse(data);
        var grid = new GridFromHtml(options, id);
        return grid;
    return null;

And when you're ready, call that function.
   var tableGrid = loadTable('tableData', 'tableGrid');

That was fairly painless.

Now for the fun part that I wanted to show off. Adding a footer to display a total. I'll reiterate that this is a way, not the best way.

The basic idea is to prepare an entry similar to the data entries, render a row, and put it in the footer. It uses the same basic formula of putting that data into a hidden HTML element, loading it, parsing it, and rendering it.

I've added an entry to store the totals data. Leave the first two columns blank, and populate the total in the value column.

My Table


Now turn on the footer, load the footer, render it, and resize so the grid body can apply the right styles and not overwrite the last row in the grid.

   var tableGrid = loadTable('tableData', 'tableGrid', {showFooter: true});

   var tableTotals = dom.byId('tableTotalsData');
   tableTotals = tableTotals.value;
   tableTotals = JSON.parse(tableTotals);

   var footer = tableGrid.renderRow(tableTotals, {});
   footer = put('div.dgrid-totals', footer);
   put(tableTotals.footerNode, footer);


Now we just need a little CSS to make sure the cells in the footer are aligned with the main content, and take the scroll bar into account.

.dgrid-footer .dgrid-totals {
    margin-right: 17px;

I wrap the rendered footer row in a div.dgrid-totals element, because it may not be the only footer on the table, especially if you're using pagination instead of on demand.

And there you have it.  Simple table data looking sexy with the rest of your Dojo themed site.

Wednesday, May 23, 2012

Saving HABTM for existing records in CakePHP 2.1

This is more of a note for me, since I was doing it wrong, and I couldn't find a clear example in the CakePHP manuals.

The scenario is saving a hasAndBelongsToMany (HABTM) relationship for existing records, and requiring a uniqueness constraint on the join table.  The solution is to use saveAssociated(). The array to pass as the data should look something like this.

$data = array(
    'Model' => array('id' => 1),
    'AssociatedModel' => array(
        array('associated_model_id' => 1),
        array('associated_model_id' => 2)

The AssociatedModel is actually the name of the hasAndBelongsToMany relationship found on the Model model, and will represent the actual join table, which will probably be called models_associated_models.