Copyright (C) 2008 by Nik Ogura. All rights reserved.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

Bug reports and comments to





        use CGI::Lazy;

        our $q = CGI::Lazy->new({

                                        tmplDir         => "/templates",

                                        jsDir           =>  "/js",

                                        plugins         => {

                                                mod_perl => {

                                                        PerlHandler     => "ModPerl::Registry",

                                                        saveOnCleanup   => 1,


                                                dbh     => {

                                                        dbDatasource    => "dbi:mysql:somedatabase:localhost",

                                                        dbUser          => "dbuser",

                                                        dbPasswd        => "letmein",

                                                        dbArgs          => {"RaiseError" => 1},


                                                session => {

                                                        sessionTable    => 'SessionData',

                                                        sessionCookie   => 'frobnostication',

                                                        saveOnDestroy   => 1,

                                                        expires         => '+15m',




        my $widget = $q->widget->dataset({

                                id              => 'detailBlock',

                                type            => 'multi',

                                template        => "lazydemoDetailBlock.tmpl",

                                headings        => {
                                                        template        => 'pathwidgetheader.tmpl',

                                                        id              => 'pathwidgetheader',

        #                                       nodelete        => 1,

                                lookups         => {

                                                prodcodeLookup  => {

                                                        sql             => 'select ID, description from prodCodeLookup', 

                                                        preload         => 1,

                                                        orderby         => ['ID'],

                                                        output          => 'hash',

                                                        primarykey      => 'ID',




                                recordset       => $q->db->recordset({

                                                        table           => 'detail', 

                                                        fieldlist       => [

                                                                                {name => 'detail.ID', 

                                                                                        hidden => 1},

                                                                                {name => 'invoiceid', 

                                                                                        hidden => 1},

                                                                                {name => 'prodCode', 

                                                                                        label => 'Product Code', 

                                                                                        validator => {rules => ['/\d+/'], msg => 'number only, and is required'}},

                                                                                {       name            => 'quantity', 

                                                                                        label           => 'Quantity', 

                                                                                        validator       => {rules => ['/\d+/'], msg => 'number only, and is required'},

                                                                                        outputMask      => "%.1f",


                                                                                {name => 'unitPrice', 

                                                                                        label           => 'Unit Price' , 

                                                                                        validator       => {rules => ['/\d+/'], msg => 'number only, and is required'},

                                                                                        inputMask       => "%.1f",


                                                                                {name => 'productGross', 

                                                                                        label => 'Product Gross' , 

                                                                                        validator => {rules => ['/\d+/'], msg => 'number only, and is required'}},

                                                                                {name => 'prodCodeLookup.description', 

                                                                                        label => 'Product Description', 

                                                                                        readOnly => 1 },


                                                        where           => '', 

                                                        joins           => [

                                                                                {type => 'inner', table => 'prodCodeLookup', field1 => 'prodCode', field2 => 'prodCodeLookup.ID',},


                                                        orderby         => 'detail.ID', 

                                                        primarykey      => 'detail.ID',



CGI::Lazy::Widget::Dataset is, at present, the crown jewel of the CGI::Lazy framework, and the chief reason why the framework was written. Lazy was written because the author has been asked to write front ends to simple databases so often that he started to realize he was writing the same damn code over and over again, and finally got sick of it.

When we're talking about web-based access to a database, there really aren't many operations that we are talking about performing. It all comes down to Select, Insert, Update, and Delete (and Ignore- but more on that later). From the standpoint of the database, it doesn't matter what the data is pertaining to, it could be cardiac patients, or tootsie rolls- the data is still stored in tables, rows and fields, and no matter what you need to read it, modify it, extend it, or destroy it.

The Dataset is designed to, given a set of records, defined by a CGI::Lazy::DB::Recordset object, display that recordset to the screen in whatever manner you like (determined by template and css) and then keep track of the data. It's smart enough to know if a record was retrieved from the db, and therefore should be updated or deleted, or if it came from the web, it must be inserted (or ignored, if it was created clientside, and then subsequently deleted clientside- these records will show on the screen, but will be ignored on submit).

Furthermore, as much of the work as possible is done clientside to cut down on issues caused by network traffic. It's using AJAX and JSON, but there's no eval-ing. All data is passed into the browser as JSON, and washed though a JSON parser.

To do it's magic, the Dataset relies heavily on javascript that *should* work for Firefox and IE6. At the time of publication, all funcitons and methods work flawlessly with FF2, FF3, and IE6. The author has tried to write for W3C standards, and provide as much IE support as his corporate sponsors required. YMMV. Bug reports are always welcome, however we will not support IE to the detrement of W3C standards. Get on board M$.

The API for Lazy, Recordset, and Dataset allows for hooking simple widgets together to generate not-so-simple results, such as pages with Parent/Child 1 to Many relationships between the Datasets. CGI::Lazy::Composite is a wrapper designed to connect Widgets, especially Datasets, together.


contents (args)

Generates widget contents based on args.


Hash of arguments. Common args are mode => 'blank', for displaying a blank data entry form, and nodiv => 1, for sending the contents back without the surrounding div tags (javascript replaces the contents of the div, and we don't want to add another div of the same name inside the div).

display (args)

Displays the widget initially. Calls $self->contents, and adds preload lookups and instance specific javascript that will not be updated on subsequent ajax calls.


Hash of arguments

displaySingleList (args)

Handler for displaying data when a search returns multiple records. Displays multipleTemplate rather than template.


Hash of arguments.

empty ()

Returns the empty property. Property gets set when a search returns nothing.

multi ()

Returns multi property. Multi gets set when a search returns more than one record.

new (q, vars)



CGI::Lazy object.


Hashref of object configs.

        class                   => widget class name (lowercase, just as if you were calling $q->widget->$classname)  (only necessary if creating widgets automatically, such as members of a Composite widget)

        id                      => widget id                    (manditory)
        type                    => widget type                  (manditory)  'single' or 'multi'

        template                => standard template            (manditory)

        multipleTemplate        => multiple template            (manditory if your searches could ever return multiple results)

        headings                => 'none'                       No headings displayed on a multi dataset.  If it's anyting other than 'none' its assumed to be the name of a template

        headings                => 'template name'              template to use for headings.  Integral div tags assumed.  

        recordset               => CGI::Lazy::RecordSet         (manditory)  Can pre-make recordset and pass object reference, or just pass hashref with recordset's particulars, and it'll get created on the fly.

        flagColor               => color to flag fields that fail validation (defaults to red)   (optional)

        lookups                 =>                              (optional)

                countryLookup =>        name of lookup 

                        sql             => sql

                        preload         => 1 (0 means no preload, will have to be run via ajax)

                        orderby         => order by clause

                        output          => type of output (see CGI::Lazy::DB)

                        primarykey      => primary key

        extravars               =>  Extra variables to be output to template    (optional)              

                                name    => name of variable

                                        value => variable, string, or reference