Implementing Province => City dependency
Tuesday 18 January 2011 8:39:55 am
- Currently 5 out of 5 Stars.
- 1
- 2
- 3
- 4
- 5
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!