#===========================================================================
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 nik.ogura@gmail.com.
CGI::Lazy::Ajax::Composite
use CGI::Lazy; our $q = CGI::Lazy->new('/path/to/config/file'); our $composite = $q->ajax->composite({ id => 'stuff', type => 'parentChild', relationship => { parent => { name => 'parentWidget', searchLike => '%?%', searchDiv => 1, }, children => { activity => { parentKey => 'advertiser.ID', childKey => 'advertiserID', }, }, }, members => [ ... ], );
Composite is a container for other widgets. It allows you to perform actions on multiple widgets at once. Depending on the relationship between the widgets, and how fancy you get, you may need to play with each subwidget by hand. Otherwise, you can specify a type, and use a prebuilt type.
parentChild is a widget that has one widget as the parent, and one or more set up as it's children. Searching on the parent will return child records that match the parent's results. Likewise dbwrite will call appropriate methods on all the children based on the widget's construction.
parentChild is pretty experimental. The configuration given in the example works fine, but I'm not yet convinced the structure is abstracted enough to work for any given group of widgets. Time will tell, and bugreports/comments.
returns blank versions of all member widgets.
Runs select query on parameters incoming via ajax call for all member widgets based on widget type. Returns results formatted for return to browser via ajax handler.
Writes to database for all member widgets based on widget type.
Returns array of composite widget's members
Returns hashref of composite widget's members
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).
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
Constructor.
CGI::Lazy object.
Hashref of object configs.
id => widget id (manditory)
members => arrayref of member widgets (manditory)
Javascript:
#these functions are built into a dataset, but at present have to be written manually for a composite # javascript functions for recieving search results for a composite widget function compositeReturn(text) { var incoming = JSON.parse(text); var html = incoming.html; parentController.validator = incoming.validator.parent; childController.validator = incoming.validator.child; document.getElementById('stuff').innerHTML = html; } #validation of both parent and child on submit function pageValidate() { var parentstate = parentController.validate(); var childstate = childController.validate(); if (parentstate && childstate) { return true; } else { return false; } } # javascript functions for searching a parent/child widget composite function compositesearch () { list = ['parent-field1', 'parent-field2', 'parent-field3']; var outgoing = {}; for (i in list) { outgoing[list[i]] = document.getElementById(list[i]).value; } var compositeSend; ajaxSend(compositeSend, outgoing, compositeReturn); }
Perl: #!/usr/bin/perl
use strict; use warnings; use CGI::Lazy; our $var = undef; our $ref = \$var; #ref to tie parts together. our $q = CGI::Lazy->new('/path/to/config/file'); our $composite = $q->ajax->composite({ id => 'stuff', type => 'parentChild', relationship => { parent => { name => 'parentWidget', searchLike => '%?%', searchDiv => 1, }, children => { activity => { parentKey => 'advertiser.ID', childKey => 'advertiserID', }, }, }, members => [ $q->ajax->dataset({ id => 'advertiser', type => 'single', multiType => 'list', containerId => 'stuff', template => 'cscAdvertiser.tmpl', multipleTemplate => 'cscAdvertiserMulti.tmpl', extravars => { advertiserID => { value => $id, }, }, recordset => $q->db->recordset({ table => 'advertiser', fieldlist => [ {name => 'advertiser.ID', label => 'Adv#', handle => $id}, {name => 'advertiser.companyname', label => 'Company:', multi => 1}, {name => 'advertiser.repid', label => 'Account Rep:', multi => 1}, {name => 'advertiser.address', label => 'Address:', multi => 1}, {name => 'advertiser.city', label => 'City:', multi => 1}, {name => 'advertiser.state', label => 'State:'}, {name => 'advertiser.postalcode', label => 'Zip:'}, {name => 'advertiser.country', label => 'Country'}, {name => 'advertiser.contactphone', label => 'Phone:'}, {name => 'advertiser.contactfax', label => 'Fax:'}, {name => 'advertiser.contactnamefirst', label => 'Contact:' }, {name => 'advertiser.contactnamelast', label => '', noLabel => 1}, {name => 'advertiser.contactemail', label => 'Email:'}, {name => 'advertiser.website', label => 'Website:'}, {name => 'advertiser.notes', label => 'Notes:'}, {name => 'salesrep.namefirst', noLabel => 1}, {name => 'salesrep.namelast', noLabel => 1} ], basewhere => '', orderby => 'advertiser.ID', primarykey => 'advertiser.ID', joins => [ {type => 'inner', table => 'salesrep', field1 => 'salesrep.ID', field2 => 'advertiser.repid',}, ], insertadditional => { advertiserID => { sql => 'select LAST_INSERT_ID()', handle => $id, }, }, }), }), $q->ajax->dataset({ id => 'activity', type => 'multi', template => "cscActivity.tmpl", recordset => $q->db->recordset({ table => 'activity', fieldlist => [ {name => 'advertiserID', hidden => 1}, {name => 'activity.ID', label => 'Item#'}, {name => 'sortdate', label => 'RunDate'}, {name => 'issue', label => 'Location'}, {name => 'page', label => 'Page'}, {name => 'description', label => 'Description', nolabel => 1}, {name => 'type', label => 'Type', nolabel => 1}, {name => 'activity.notes', label => 'Notes', nolabel => 1}, ], basewhere => '', orderby => 'activity.ID', primarykey => 'activity.ID', }), }), ], ); my %nav = ( dbwrite => \&dbwrite, ); if ($q->param('nav')) { $nav{$q->param('nav')}->(); } elsif ($q->param('POSTDATA')) { ajaxHandler(); } else { display('blank'); } #---------------------------------------------------------------------------------------- sub ajaxHandler { my $incoming = from_json($q->param('POSTDATA') || $q->param('keywords')); if ($incoming->{delete}) { doFullDelete($incoming); return; } print $q->header, $composite->ajaxSelect($incoming); return; } #---------------------------------------------------------------------------------------- sub dbwrite { $composite->dbwrite(); display('blank'); } #---------------------------------------------------------------------------------------- sub display { my $mode = shift; print $q->header, $q->start_html({-style => {src => '/css/style.css'}}), $q->javascript->modules($composite); #javascript functions needed by widget #header section print $q->template('sometemplate.tmpl')->process({ mainTitle => 'Main Title', secondaryTitle => 'Secondary Title', versionTitle => 'version 0.1', messageTitle => 'blah blah blah', }); #composite widget section print $q->start_form({ -id => 'mainForm'}), $q->hidden({-name => 'nav', -value => 'dbwrite'}); print $composite->display(mode => $mode); print $composite->q->jsload('somejavascript.js'); print $q->end_form; print $q->template('someothertemplate.tmpl')->process({version => $q->lazyversion}); return; }
To install CGI::Lazy, copy and paste the appropriate command in to your terminal.
cpanm
cpanm CGI::Lazy
CPAN shell
perl -MCPAN -e shell install CGI::Lazy
For more information on module installation, please visit the detailed CPAN module installation guide.