Implementing Province => City dependency

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!

Powered by eZ Publish™ CMS Open Source Web Content Management. Copyright © 1999-2014 eZ Systems AS (except where otherwise noted). All rights reserved.

eZ debug

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

Main resources:

Total runtime0.1000 sec
Peak memory usage6,144.0000 KB
Database Queries42

Timing points:

CheckpointStart (sec)Duration (sec)Memory at start (KB)Memory used (KB)
Script start 0.00000.0068 588.0313152.6406
Module start 'layout' 0.00680.0047 740.671939.4688
Module start 'content' 0.01160.0869 780.1406386.1719
Module end 'content' 0.09840.0015 1,166.312519.7031
Script end 0.0999  1,186.0156 

Time accumulators:

 Accumulator Duration (sec) Duration (%) Count Average (sec)
Ini load
Load cache0.00383.7747150.0003
Check MTime0.00131.3000150.0001
Mysql Total
Database connection0.00080.758110.0008
Mysqli_queries0.038438.4204420.0009
Looping result0.00040.4076400.0000
Template Total0.063063.020.0315
Template load0.00202.050520.0010
Template processing0.060960.904920.0304
Template load and register function0.00010.097110.0001
states
state_id_array0.00111.113210.0011
state_identifier_array0.00090.877420.0004
Override
Cache load0.00181.8105510.0000
Sytem overhead
Fetch class attribute name0.00201.953430.0007
class_abstraction
Instantiating content class attribute0.00000.009130.0000
General
dbfile0.00080.7760100.0001
String conversion0.00000.011040.0000
Note: percentages do not add up to 100% because some accumulators overlap

Templates used to render the page:

UsageRequested templateTemplateTemplate loadedEditOverride
1node/view/full.tplblog_entry/full.tplextension/community_design/design/suncana/override/templates/blog_entry/full.tplEdit templateOverride template
2content/datatype/view/ezxmltext.tpl<No override>extension/community_design/design/suncana/templates/content/datatype/view/ezxmltext.tplEdit templateOverride template
15content/datatype/view/ezxmltags/paragraph.tpl<No override>extension/ezwebin/design/ezwebin/templates/content/datatype/view/ezxmltags/paragraph.tplEdit templateOverride template
7content/datatype/view/ezxmltags/strong.tpl<No override>design/standard/templates/content/datatype/view/ezxmltags/strong.tplEdit templateOverride template
7content/datatype/view/ezxmltags/literal.tpl<No override>extension/community/design/standard/templates/content/datatype/view/ezxmltags/literal.tplEdit templateOverride template
2content/datatype/view/ezxmltags/emphasize.tpl<No override>design/standard/templates/content/datatype/view/ezxmltags/emphasize.tplEdit templateOverride template
1content/datatype/view/ezkeyword.tpl<No override>extension/community_design/design/suncana/templates/content/datatype/view/ezkeyword.tplEdit templateOverride template
1print_pagelayout.tpl<No override>extension/community/design/community/templates/print_pagelayout.tplEdit templateOverride template
 Number of times templates used: 36
 Number of unique templates used: 8

Time used to render debug report: 0.0001 secs