Adding javascript to symfony form field

In the users table at my company’s website there are fields for company, division, region, and location. Since each level of the company organization affects all the lower categories I have to filter out the invalid choices when a higher level choice is selected.

I’ve implemented this on some forms that I’ve created manually on the site but not in any forms that I haven’t heavily modified from the stock symfony creation.  I started googling around to find a solution but could not find a simple explanation of how to do it.  I expected to find at least some information in one of symfony’s otherwise excellent tutorials, but alas, no.

I had a minor epiphany and went digging through the forms API that symfony provides and realized that I should easily be able to do this through the sfWidgetFormPropelChoice method.  The second parameter passed is the html attributes for the form field.  I thought I had seen a form post here that said that I could add javascript code to the html attributes and not have it get converted into html entities.

I tried throwing a simple alert() inside the onchange attribute for my company box and wham! it worked!  So simple.  Code below:

new sfWidgetFormPropelChoice(
	array(
		'model' => 'Company',
		'add_empty' => true
	),
	array(
		'onchange' => "filterBy('company', 'division', this.value, 'sf_guard_user_user_division_id');" .
			"filterBy('company', 'region', this.value, 'sf_guard_user_user_region_id');" .
			"filterBy('company', 'location', this.value, 'sf_guard_user_user_location_id');"
	)
)

Till Next Time

Tags: , , , , , ,

2 Responses to “Adding javascript to symfony form field”

  1. Suborno says:

    Hi,
    I need this solution. Where is your filterBy() function? Can i get it?
    I’m stuck on that problem.

    Thanks

  2. Patrick says:

    @Suborno

    here’s the js that I use, it’s not beautiful, but it works:

    // handles overall function control
    function filterBy(filter_type, result_type, filter_value, field, preshot, select_option)
    {
    try
    {
    httpRequest = createFinalHttpRequest();
    if(httpRequest != null)
    {
    /*
    * the two items commented out below are what need to be uncommented if you want
    * asynchronous transfer.
    * A bug exists in the select box filtering when you trigger this event more than
    * once on a single event
    *
    * (i.e.- New Location page, when user selects the Company, Division and Region
    * are both automatically populated with appropriate options)
    *
    */
    var location = ‘/activity/filter?filter_type=’ + filter_type + ‘&result_type=’ + result_type + ‘&filter_value=’ + filter_value;
    httpRequest.open(“GET”, location, false);
    httpRequest.send(null);

    if(httpRequest.readyState == 4)
    {
    if(httpRequest.status == 200)
    {
    var response_header = httpRequest.getResponseHeader(“Content-Type”);
    if(response_header.indexOf(“text/xml”) != -1 || response_header.indexOf(“application/xml”) != -1)
    {
    var xml = httpRequest.responseXML;
    if(xml)
    var results = parseFilterResults(xml, result_type);
    if(!results)
    alert(‘There has been an error filtering the results’);
    else
    {
    if(select_option)
    filterBox(field, results, select_option);
    else
    filterBox(field, results);
    }
    }
    else
    alert(‘Content is NOT xml;\nContent is: ‘ + httpRequest.getResponseHeader(“Content-Type”));
    }
    }
    }
    else
    alert(“The http request is null!”);
    }
    catch(err)
    {
    alert(“There was an error filtering the ” + result_type + “: ” + err);
    return false;
    }
    return true;

    }

    // creates the actual xml request to server
    function createFinalHttpRequest()
    {
    var xmlhttp;
    if (window.XMLHttpRequest)
    {
    // code for IE7+, Firefox, Chrome, Opera, Safari
    xmlhttp = new XMLHttpRequest();
    }
    else
    {
    // code for IE6, IE5
    try
    {
    xmlhttp = new ActiveXObject(“Msxml2.XMLHTTP”);
    }
    catch(err)
    {
    try
    {
    xmlhttp = new ActiveXObject(“Microsoft.XMLHTTP”);
    }
    catch(er)
    {
    xmlhttp = null;
    }
    }
    }
    return xmlhttp;
    }

    // parses the returned xml and creates an array of the values
    function parseFilterResults(xml, type)
    {
    try
    {
    var results = new Array();
    switch(type)
    {
    case ‘division’:
    var divs = xml.getElementsByTagName(type);
    var ids = xml.getElementsByTagName(‘id’);
    var names = xml.getElementsByTagName(‘name’);
    for(var i=0;i {
    var id = ids[i].childNodes[0].nodeValue;
    var name = names[i].childNodes[0].nodeValue;
    results.push(new Array(id, name));
    }
    break;
    case 'region':
    var regs = xml.getElementsByTagName(type);
    var ids = xml.getElementsByTagName('id');
    var names = xml.getElementsByTagName('name');
    for(var i=0;i {
    var id = ids[i].childNodes[0].nodeValue;
    var name = names[i].childNodes[0].nodeValue;
    results.push(new Array(id, name));
    }
    break;
    case 'location':
    var locs = xml.getElementsByTagName(type);
    var ids = xml.getElementsByTagName('id');
    var names = xml.getElementsByTagName('name');
    for(var i=0;i {
    var id = ids[i].childNodes[0].nodeValue;
    try
    {
    var name = names[i].childNodes[0].nodeValue;
    }
    catch(ee)
    {
    var name = "";
    }
    results.push(new Array(id, name));
    }
    break;
    case 'seismo':
    var seismos = xml.getElementsByTagName(type);
    var ids = xml.getElementsByTagName('id');
    var names = xml.getElementsByTagName('name');
    var lats = xml.getElementsByTagName('lat');
    var longs = xml.getElementsByTagName('long');
    for(var i=0;i {
    var id = ids[i].childNodes[0].nodeValue;
    var name = names[i].childNodes[0].nodeValue;
    try
    {
    var lat = lats[i].childNodes[0].nodeValue;
    var long = longs[i].childNodes[0].nodeValue;
    }
    catch(e)
    {
    var lat = "";
    var long = "";
    }
    results.push(new Array(id, name, lat, long));
    }
    break;
    case 'activity':
    var activities = xml.getElementsByTagName(type);
    var ids = xml.getElementsByTagName('id');
    var shot_numbers = xml.getElementsByTagName('shot_number');
    for(var i=0;i {
    var id = ids[i].childNodes[0].nodeValue;
    try
    {
    var shot_number = shot_numbers[i].childNodes[0].nodeValue;
    }
    catch(ee)
    {
    var shot_number = "";
    }
    results.push(new Array(id, shot_number));
    }
    default: // company
    break;
    }
    }
    catch(err)
    {
    alert("There was an error parsing the results: " + err);
    return false;
    }
    return results;

    }

    // this removes all the options in the given box and adds all the new
    // options in the options array
    function filterBox(field, options, select_option)
    {
    try
    {
    var updated_field = document.getElementById(field);
    removeAllOptions(updated_field, false);
    if(select_option)
    addSelectOption(updated_field, "", "Select an Option");
    for(var i=0;i addSelectOption(updated_field, options[i][0], options[i][1]);
    }
    catch(err)
    {
    alert("There has been an erroring filtering the dropdown box: " + err);
    return false;
    }
    return true;
    }

    // removes all options from a select box with the option
    // to add a single 'blank' value option back
    function removeAllOptions(sel_box, keep_blank)
    {
    try
    {
    for(var i=sel_box.length-1;i>=0;i–)
    sel_box.remove(i);
    if(keep_blank)
    addSelectOption(sel_box, “”, “Select an Option”);
    }
    catch(err)
    {
    alert(“There has been an error removing options: ” + err);
    return false;
    }
    return true;
    }

    // adds an option to a select box
    function addSelectOption(field, value, text)
    {
    try
    {
    var opt = document.createElement(“option”);
    opt.text = text;
    opt.value = value;
    field.options.add(opt);
    }
    catch(err)
    {
    alert(“There was an error adding an option: ” + err);
    return false;
    }
    return true;
    }

Leave a Reply