Tuesday 18 January 2011 8:39:55 am
By : Henrik Gren
Hi everyone!
Since I notice that there are quite some posts on this topic, I thought I should share with you how I implemented a form where one field depends on another. I will use the classic example where the user selects a province and then is limited in his choice of choosing a city only to those cities that actually exist in that province.
The final result can be seen here: http://www.colussigroup.it/index.php/Chiedi-Informazioni (the fields are provincia and comune).
Step1: Create the DB Tables
For the provinces:
CREATE TABLE province ( id mediumint(9) NOT NULL, `name` char(2) default NULL, PRIMARY KEY (id) );
For the cities:
CREATE TABLE comuni ( id mediumint(9) NOT NULL auto_increment, comune varchar(100) default NULL, provincia char(2) default NULL, pid mediumint(9) default NULL, PRIMARY KEY (id) );
Step 2: Create a custom data type for the province combo box
I used the integrate extension developed by Bruce Morrison here:
http://pubsvn.ez.no/community/trunk/extension/integrate/
Of course you can develop your own data type, but since Bruce did a really nice job here I recommend you use it.
Check the README file for installation instructions.
Step 3: Create the form
For those who are not familiar with the creation of eZ Publish forms, here is the tutorial: http://share.ez.no/learn/ez-publish/how-to-create-ez-publish-forms/(language)/eng-GB.
The two fields of the form that interest us were created in this way:
Provincia [External Option] - Table: Province - Index Column: id - Name Column: name
Comune [Text line] - Default Value: Empty
In the chiedi_informazioni.tpl, the code for the two fields is:
<select class="formelement" id="prov" name="ContentObjectAttribute_data_int_{$node.data_map.provincia.id}" style="width: 155px;"> <option value="">Seleziona la provincia</option> {section loop=$node.data_map.provincia.content.options} <option value="{$item.val|wash(xhtml)}"{if eq($value, $item.val)} selected="selected"{/if}>{$item.label|wash(xhtml)}</option> {/section} </select>
and:
<input type="text" value="" name="ContentObjectAttribute_ezstring_data_text_{$node.data_map.comune.id}" id="city" class="formelement" style="width: 150px;" />
At this point we have a fully functioning form, but we are missing the last bit (the purpose of this post): The dependency. We accomplish this in two steps: Creating an ezjscore extension and adding a little bit of jQuery to our .tpl.
Step 4: Create the extension
There is the ezjscore tutorial here: http://share.ez.no/learn/ez-publish/ezjscore-ez-publish-javascript-and-ajax-framework. I spent a few days before I could connect all the pieces. Probably I was lacking some jQuery skills and for this particular case you would find that information here: http://docs.jquery.com/Plugins/autocomplete.
If you don't have ezjscore already, as part of ezflow or ezwebin you should install it first.
This is the code that you should put in your /extension/yourextension/classes/extensionfunction.php (in my case it is /extension/citycomplete/classes/completecityfuncion.php).
<?php class completeCityFunction extends ezjscServerFunctions { public static function searchCities($args) { $query = ''; $db =& eZDB::instance(); $http = eZHTTPTool::instance(); $query="select distinct(comune) from comuni where comune like '".trim($http->getVariable( 'q' ))."%' and pid ='".$http->getVariable( 'province' )."'"; $result = $db->arrayQuery($query); return $result; var_dump($result); } } ?>
I made this extension available through the admin interface and I put it in the site.ini.append.php in the /settings/override directory (you could choose any other of a number of options depending on your needs):
[ExtensionSettings] ActiveExtensions[]=citycomplete
For further information on HOWTO with extensions, read: http://share.ez.no/learn/ez-publish/an-introduction-to-developing-ez-publish-extensions.
Step 5: Write the Javascript
Simply, here is the code. If you stray from it, you will find trouble.
$(document).ready(function(){ $("#city").autocomplete('/index.php/ezjscore/call/citycomplete::searchCities', { dataType: "json", mustMatch: true, minChars: 1, parse: function(data) { return $.map(data.content, function(row) { return { data: row.comune, value: row.comune, result: row.comune } }); }, formatItem: function(item) { return item; }, extraParams: { province: function() { return $("#prov").val();} } }); }
Note: If you prefer, you could substitute the combo-box with a text box. In that case you would not need Bruce's datatype anymore, you would have to add a new extension, similar to the citycomplete extension, and you would need to modify you SQL a little.
Ciao!
Timing: | Jan 18 2025 01:00:00 |
Script start | |
Timing: | Jan 18 2025 01:00:00 |
Module start 'layout' | |
Timing: | Jan 18 2025 01:00:00 |
Module start 'content' | |
Timing: | Jan 18 2025 01:00:00 |
Module end 'content' | |
Timing: | Jan 18 2025 01:00:00 |
Script end |
Total runtime | 0.1000 sec |
Peak memory usage | 6,144.0000 KB |
Database Queries | 42 |
Checkpoint | Start (sec) | Duration (sec) | Memory at start (KB) | Memory used (KB) |
---|---|---|---|---|
Script start | 0.0000 | 0.0068 | 588.0313 | 152.6406 |
Module start 'layout' | 0.0068 | 0.0047 | 740.6719 | 39.4688 |
Module start 'content' | 0.0116 | 0.0869 | 780.1406 | 386.1719 |
Module end 'content' | 0.0984 | 0.0015 | 1,166.3125 | 19.7031 |
Script end | 0.0999 | 1,186.0156 |
Accumulator | Duration (sec) | Duration (%) | Count | Average (sec) |
---|---|---|---|---|
Ini load | ||||
Load cache | 0.0038 | 3.7747 | 15 | 0.0003 |
Check MTime | 0.0013 | 1.3000 | 15 | 0.0001 |
Mysql Total | ||||
Database connection | 0.0008 | 0.7581 | 1 | 0.0008 |
Mysqli_queries | 0.0384 | 38.4204 | 42 | 0.0009 |
Looping result | 0.0004 | 0.4076 | 40 | 0.0000 |
Template Total | 0.0630 | 63.0 | 2 | 0.0315 |
Template load | 0.0020 | 2.0505 | 2 | 0.0010 |
Template processing | 0.0609 | 60.9049 | 2 | 0.0304 |
Template load and register function | 0.0001 | 0.0971 | 1 | 0.0001 |
states | ||||
state_id_array | 0.0011 | 1.1132 | 1 | 0.0011 |
state_identifier_array | 0.0009 | 0.8774 | 2 | 0.0004 |
Override | ||||
Cache load | 0.0018 | 1.8105 | 51 | 0.0000 |
Sytem overhead | ||||
Fetch class attribute name | 0.0020 | 1.9534 | 3 | 0.0007 |
class_abstraction | ||||
Instantiating content class attribute | 0.0000 | 0.0091 | 3 | 0.0000 |
General | ||||
dbfile | 0.0008 | 0.7760 | 10 | 0.0001 |
String conversion | 0.0000 | 0.0110 | 4 | 0.0000 |
Note: percentages do not add up to 100% because some accumulators overlap |
Usage | Requested template | Template | Template loaded | Edit | Override |
---|---|---|---|---|---|
1 | node/view/full.tpl | blog_entry/full.tpl | extension/community_design/design/suncana/override/templates/blog_entry/full.tpl | ||
2 | content/datatype/view/ezxmltext.tpl | <No override> | extension/community_design/design/suncana/templates/content/datatype/view/ezxmltext.tpl | ||
15 | content/datatype/view/ezxmltags/paragraph.tpl | <No override> | extension/ezwebin/design/ezwebin/templates/content/datatype/view/ezxmltags/paragraph.tpl | ||
7 | content/datatype/view/ezxmltags/strong.tpl | <No override> | design/standard/templates/content/datatype/view/ezxmltags/strong.tpl | ||
7 | content/datatype/view/ezxmltags/literal.tpl | <No override> | extension/community/design/standard/templates/content/datatype/view/ezxmltags/literal.tpl | ||
2 | content/datatype/view/ezxmltags/emphasize.tpl | <No override> | design/standard/templates/content/datatype/view/ezxmltags/emphasize.tpl | ||
1 | content/datatype/view/ezkeyword.tpl | <No override> | extension/community_design/design/suncana/templates/content/datatype/view/ezkeyword.tpl | ||
1 | print_pagelayout.tpl | <No override> | extension/community/design/community/templates/print_pagelayout.tpl | ||
Number of times templates used: 36 Number of unique templates used: 8 |
Time used to render debug report: 0.0001 secs