Snippets

Create an account or login to be able to add, comment and rate snippets.

Navigation

cascading combo 2-level mulit-select list

There are two multi-select box, the first one is parent list menu, the second one is child menu; when clicking item in first list, its submenu will appear in second list, then you can multi-select from 2nd list; and you can multi-select items in 1st list by clicking, double-click, ctrl+click, shift+click, all selected items in 1st list will display their children in 2nd list, all deselected items from 1st list will remove their children from 2nd list. This combo list can be used for select HOBBIES, TYPES, CATEGORIES etc.

*** in multiselSuccess.php:

<script type="text/javascript" src="/sf/js/prototype/prototype.js"></script>
<body onload="new Ajax.Request('/news/select/level/province', {asynchronous:true, evalScripts:false, onComplete:function(request, json){updateJSON(request,json,1)}}); return false;" >

*** in multiselSuccess.php:

<?php
            echo select_tag("province",options_for_select(Array(''=>'-Select-')),'multiple=multiple size=10  onmousedown=GetCurrentListValues(this); onchange=javascript:loadCity(\''.sfConfig::get('app_site_url').'news/select/level/city\',this)');
            echo select_tag('city[]',options_for_select(Array(''=>'-Select-')),'multiple=multiple size=10');
            ?>
            <div id=statusTxt></div>

*** in view.yml:

selectSuccess:
  has_layout: off

*** javascript can be written in multiselSuccess.php, or in another javascript file multiselSuccess.js: if written in a seperate file multiselSuccess.js, put it under PROJECT_NAME\web\js\, and in ...\apps\APPLICATION_NAME\config:

    javascripts:    [multiselSuccess.js ]

<script language="javascript">
<!--//
/**
 * ajax no refresh cascading 2-level menu
 *
 */
function loadCity(url,CONTROL) {                            //load city
 
    var strTmp=provinceChanged(CONTROL);                    //result format: +provinceId or -provinceId
    var provChg=strTmp.split(",");
    url=url+"/id/"+provChg[0];                              //provChg[0]: item value of first menu; url: /news/select/level/city/id/ItemValueOfFirstMenu
    new Ajax.Request(url, {asynchronous:true, evalScripts:false, onComplete:function(request, json){updateJSON(request,json,2,provChg[1])}});
    return false;
}
 
var arrOldValues;
function GetCurrentListValues(CONTROL){
    var strValues = "";
    strValues = GetSelectValues(CONTROL);
    arrOldValues = strValues.split(",")
}
 
function GetSelectValues(CONTROL){
    var strTemp = "";
    for(var i = 0;i < CONTROL.length;i++){
        if(CONTROL.options[i].selected == true){
            strTemp += "1,";
        }
        else{
            strTemp += "0,";
        }
    }
    return strTemp;
}
 
function provinceChanged(CONTROL){
    var strTemp = GetSelectValues(CONTROL);
    arrNewValues = strTemp.split(",");
    var sum=0;
    for(var i=0;i<arrNewValues.length-1;i++){
        sum+=eval(arrNewValues[i]);
        if (sum >= 2){                                      //more than 1 are selected
            break;
        }
        if (arrNewValues[i] == 1){                          //when this condition is met, sum must be 1
            var selectedPos=i;
        }
    }
 
    if (sum==0){                                            //deselect all by ^Click; remove all from 2nd menu
        provChg=""+",--";
    }
    else if (sum==1){                                       //only one selected, click or ctrl+click
        if (arrOldValues[selectedPos] == 0){                //if this selcted one wasn't selected before, just add;
                                                            //at this point,arrNewValues[selectedPos] must be 1
            removeOptionAll("city");
            provChg=CONTROL.options[selectedPos].value+",+";
        }
        else{               //if this selcted one was selected before, remove all others but keep selected of this one
            removeOptionAll("city");
            provChg=CONTROL.options[selectedPos].value+",+";        //???to simplify, just add, previously selected may be lost
        }
    }
    else{       //
        for(var i=0;i<arrNewValues.length-1;i++){
            if (arrNewValues[i] != arrOldValues[i]){
                if (arrNewValues[i]==1){                    //add a new province
 
                    provChg=CONTROL.options[i].value+",+";
                }
                else{                                       //remove a new province
                    provChg=CONTROL.options[i].value+",-";
                }
            }
        }
    }
    return provChg;
}
 
/**
 * ajax no refresh 2-level cascading menu
 *
 */
function addOption(objSelectNow,txt,val)
{
    //using W3C syntax add Options for SELECT
    var objOption = document.createElement("OPTION");
    objOption.text= txt;
    objOption.value=val;
    objSelectNow.options.add(objOption);
}
 
function addOptionGroup(selectId,optGroup)
{
    var objSelect = document.getElementsByTagName("SELECT");
    var objSelectNow = objSelect[selectId];
 
    if (selectId=="province"){
        objSelectNow.length = 1;
    }
        /// add Options group
        for (i=0; i<optGroup.length; i++)
        {
            addOption(objSelectNow, optGroup[i][1], optGroup[i][0]);
        }
 
}
 
 
function removeOptionGroup(selectId,optGroup)                   //optGroup: array of 2nd menu corresponding to deselected item of 1st menu; categoryId=>categoryName
{
    var objSelect = document.getElementsByTagName("SELECT");
    var objSelectNow = objSelect[selectId];
 
    for (i=0;i<objSelectNow.length;i++){
        if (objSelectNow.options[i].value==optGroup[0][0]){     //the first position to be removed
            var bgn=i;
            break;
        }
    }
 
    /// remove Options
    for (i=0;i<optGroup.length;i++){
        objSelectNow.options.remove(bgn);
    }
}
 
function removeOptionAll(selectId)
{
    var objSelect = document.getElementsByTagName("SELECT");
    var objSelectNow = objSelect[selectId];
    for (i=1;i<objSelectNow.options.length;){
        objSelectNow.options.remove(1);
    }
}
 
function updateJSON(request, json,level,operation){
    var responses = json;
    if (!json){
      //if you don't use the json tips then evaluate the renderedText instead
      var responses = eval('(' + request.responseText + ')');
    }
    if (level==1)                                       //for 1st menu
        addOptionGroup("province",responses);
    else if (level==2){                                 //for 2nd menu
        if (operation=="+"){
            addOptionGroup("city",responses);
        }
        else if (operation=="-"){
            removeOptionGroup("city",responses);
        }
        else if (operation=="--"){
            removeOptionAll("city");
        }
    }
}
 
-->
</script>

*** in actions.classs.php:

public function executeSelect(){
    /**
     * ajax no refresh 2-level cascading menu back-end
     *
     */
    //load data:
 
    $c=new Criteria();
    $c->add(CategoryPeer::PARENT_ID,NULL);                  //get contents for 1st menu
    $categories=CategoryPeer::doSelect($c);
    $parent="";
    if ($categories){
        $i=0;
        $parent='[';
        foreach ($categories as $category){
            $name=$category->getName();
            $id=$category->getId();
            $parent=$parent.'["'.$id.'","'.$name.'"],';     //format for 1st menu: [["1","German"],["2","France"],["3","Argentina"]]
 
            //retrive records whose parent_id is..
            $c=new Criteria();
            $c->add(CategoryPeer::PARENT_ID,$category->getId());
            $categories_sub=CategoryPeer::doSelect($c);
            $city[$id]='[';                                  //index of $city[] is category id; format of $city[]:[["48","Team1.Fr"],["49","Team2.Fr"],["50","Team3.Fr"],["51","Team4.Fr"],["52","Team5.Fr"]]
            foreach ($categories_sub as $category_sub){
                $city[$id]=$city[$id].'["'.$category_sub->getId().'","'.$category_sub->getName().'"],';
            }
            $city[$id]=rtrim($city[$id],",");
            $city[$id].=']';
            $i++;
        }
    }
    $parent=rtrim($parent,",");
    $parent.=']';
 
    $level=$this->getRequestParameter('level');
    if($level=="province"||$level==""){     //level=province, output contents for first menu
         $this->output=$parent;
    }
    else if($level=="city"){                //level=city, output contents for second menu
        $id=$this->getRequestParameter('id');
        $this->output=$city[$id];
    }
    else{                                   //false
        $this->output="error when getting data";
    }
    return sfView::SUCCESS;
}

*** in selectSuccess.php:

<?php
echo $output;
?>
by William Duan on 2007-01-04, tagged ajax  javascript 

Comments on this snippet

gravatar icon
#1 Stephen Riesenberg on 2007-01-04 at 04:53

I don't get it...

You need to create an account or log in to post a comment or rate this snippet.