Create dynamic Drop Down List

2019-09-14 00:55发布

I'm searching the internet now for quite some time to find a proper solution but I was not successful so far.

What I try to achieve: I create a dynamic drop down box with provinces. As soon as the user selects one of the dynamic created entries, a second dynamic drop down box for districts should only display the proper entries depending on the selected province.

Therefor I have build the following code:

search.php

//$i is running up to the max amount of provinces
//for each province there shall be one option in the html select
//the session array provinceresults contains key1, key2, province (english), province (other language)
for($i=0; $i < $countProvinces; $i++) {

   echo "<option value=".$_SESSION['provincesresults'][$i][0]." onClick=\"removeSelected(\".$i.\")\">".$_SESSION['provincesresults'][$i][1]."</option>";
}

In the body part of the search.php I have the following JavaScript code which shall get executed when I select one of the above generated options per onClick:

<!--Javascript which is needed to call the dynamic_drop_down.php function per onClick event-->
<script type=\"text/javascript\"> 
  function removeUnselected($key){
      document.getElementById(\"php_code\").innerHTML=\"
        <?php  

           //Get all the values out of the district array out of pdo.vhd
           $districtsSelected = removeUnselected(".$_SESSION['provincesresults'][$key][0].");
           }
       ?>\"; 
  } 

So I need do get the $i counter out of the first PHP part into the Javascript function. After that I need the filled $districtsSelected for further use in my search.php

The php function removeUnselected(".$_SESSION['provincesresults'][$key][0]."); looks like this and is included in the search.php:

<?php

/**
*This php file is used to retrieve the districts for a selected province.
*This file is called by search.php.
*As input, the function needs to be called with the ID of the selected province, it will return all related districts.
*/

function removeUnselected($provinceKey) {

   //Build the array which returns the needed districts
   $districtsSelected = array();

   //Loop through all the districts that have been read out of the database by get_value_help.php
   for($i = 0; $i < count($_SESSION['districtsresults']); $i++) {

      //Check if the province id out of the table dbo.vhp matches with the id out of the table dbo.vhd
      if(strcmp($provinceKey, $_SESSION['districtsresults'][$i][1]) == 0) {

         //Give back the district names in english if the language settings are english
         if($_SESSION['lng'] == "english") {

            //Remove any districts that were not selected
            $districtsSelected[] = $_SESSION['districtsresults'][$i][2];
         }
          //Give back the district names in khmer if the language settings are khmer
         elseif ($_SESSION['lng'] == "khmer") {

            //Remove any districts that were not selected
            $districtsSelected[] = $_SESSION['districtsresults'][$i][3];
         }
      }
   }

   //Return the result
   return($districtsSelected);
}
?>

Any suggestions on how I can build this in a working way are highly appreciated!

Thank you and regards,

codac

EDIT: I am using the following JavaScript: http://www.mattkruse.com/javascript/dynamicoptionlist/index.html

I have two problems now: As there are 24 Provinces, 86 Districts, 1600 Communes and 13500 Villages, creating for drop-down boxes takes several seconds.

The tables look like this (Provinces):

country_id  province_id province_en    province_kh
000000  010000          Banteay Mean Chey  Khmer 1
000000  020000          Bat Dambang    Khmer 2
000000  030000          Kampong Cham       Khmer 3
000000  040000          Kampong Chhnang    Khmer 

(districts) province_id district_id district_en district_kh 010000 010200 Mongkol Borei Khmer 1 010000 010300 Phnum Srok Khmer 2 010000 010400 Preah Netr Preah Khmer 3 010000 010500 Ou Chrov Khmer 4

...same for communes and villages.

I get the values out of the Microsoft SQL Server via:

 $sqlProvinces = "SELECT country_id, province_id, province_en, province_kh FROM dbo.vhp";
 $sqlDistricts = "SELECT province_id, district_id, district_en, district_kh FROM dbo.vhd";

...same for communes and villages.

Like mentioned in my comment, I store these values in a $_SESSION:

$_SESSION["provincesresults"]=$provincesResults;
$_SESSION["districtsresults"]=$districtsResults;

After that I use the function "dyndrpdwn.php" to generate the drop down list:

<?php

function dyndrpdwn() {

   //count the number of provinces, districts, communes and villages for the counters of the for-statements
   $countProvinces = count($_SESSION["provincesresults"]);
   $countDistricts = count($_SESSION["districtsresults"]);
   $countCommunes = count($_SESSION["communesresults"]);
   $countVillages = count($_SESSION["villagesresults"]);

   //NULL the return values
   $returnPD = NULL;
   $returnC = NULL;
   $returnV = NULL;
   $defaultP = NULL;
   $defaultD = NULL;
   $defaultC = NULL;
   $defaultV = NULL;

   //Set start value for the counters to 0
   $j = 0;
   $k = 0;
   $l = 0;

   //Start the JavaScript and create the DynamitOptionList
   $returnPD = "<script type=\"text/javascript\">
                   var makeGeo = new DynamicOptionList(\"provinces\",\"districts\",\"communes\",\"villages\");";

   //Loop through all Provinces
   for($i = 0; $i < $countProvinces; $i++) {

      //Create the optionlist for provinces
      $returnPD = $returnPD."makeGeo.forValue(\"".$_SESSION["provincesresults"][$i][1]."\").addOptionsTextValue(";

      //Create the optionlist for districts ("while" if more performant than "for"!) and make sure that counter is not getting out of index
      while($j < $countDistricts && $_SESSION["provincesresults"][$i][1] == $_SESSION["districtsresults"][$j][0]) {

         $returnPD = $returnPD."\"".$_SESSION["districtsresults"][$j][2]."\",\"".$_SESSION["districtsresults"][$j][1]."\",";

         $returnC = $returnC."makeGeo.forValue(\"".$_SESSION["provincesresults"][$i][1]."\").forValue(\"".$_SESSION["districtsresults"][$j][1]."\").addOptionsTextValue(";

         //Create the optionlist for communes ("while" if more performant than "for"!) and make sure that counter is not getting out of index
         while($k < $countCommunes && $_SESSION["districtsresults"][$j][1] == $_SESSION["communesresults"][$k][0]) {

            $returnC = $returnC."\"".$_SESSION["communesresults"][$k][2]."\",\"".$_SESSION["communesresults"][$k][1]."\",";

            $returnV = $returnV."makeGeo.forValue(\"".$_SESSION["provincesresults"][$i][1]."\").forValue(\"".$_SESSION["districtsresults"][$j][1]."\").forValue(\"".$_SESSION["communesresults"][$k][1]."\").addOptionsTextValue(";

            //Create the optionlist for villages ("while" if more performant than "for"!) and make sure that counter is not getting out of index
            while($l < $countVillages && $_SESSION["communesresults"][$k][1] == $_SESSION["villagesresults"][$l][0]) {

               $returnV = $returnV."\"".$_SESSION["villagesresults"][$l][2]."\",\"".$_SESSION["villagesresults"][$l][1]."\",";

               //Set the Default Value
           $defaultV = "makeGeo.forValue(\"".$_SESSION["communesresults"][$k][1]."\").setDefaultOptions(\"".$_SESSION["searchresultspmd"][0][8]."\");";

               //Increase the counter by 1
               $l++;
            }

            //Cut the last "," of the string after the last value of $returnC
            $returnV = substr($returnV, 0, -1);

            //Close the JavaScript statement
            $returnV = $returnV.");";

            //If there is no village for the commune, remove the already prepared string "makeGeo.forValue(\"".$_SESSION["provincesresults"][$i][1]."\").forValue(\"".$_SESSION["districtsresults"][$j][1]."\").forValue(\"".$_SESSION["communesresults"][$k][1]."\").addOptionsTextValue("
            if(substr($returnV,-21) == "addOptionsTextValue);") {

               $returnV = substr($returnV, 0, -86);
            }

            //Set the Default Value
            $defaultC = "makeGeo.forValue(\"".$_SESSION["districtsresults"][$j][1]."\").setDefaultOptions(\"".$_SESSION["searchresultspmd"][0][7]."\");";

            //Increase the counter by 1
            $k++;
         }

         //Cut the last "," of the string after the last value of $returnC
         $returnC = substr($returnC, 0, -1);

         //Close the JavaScript statement
         $returnC = $returnC.");";

         //If there is no commune for the district, remove the already prepared string "makeGeo.forValue(\"".$_SESSION["provincesresults"][$i][1]."\").forValue(\"".$_SESSION["districtsresults"][$j][1]."\").addOptionsTextValue("
         if(substr($returnC,-21) == "addOptionsTextValue);") {

            $returnC = substr($returnC, 0, -66);
         }

         //Set the Default Value
         $defaultD = "makeGeo.forValue(\"".$_SESSION["provincesresults"][$i][1]."\").setDefaultOptions(\"".$_SESSION["searchresultspmd"][0][8]."\");";

         //Increase the counter by 1
         $j++;
      }

      //Cut the last "," of the string after the last value of $returnPD
      $returnPD = substr($returnPD, 0, -1);

      //Close the JavaScript statement
      $returnPD = $returnPD.");";

      //If there is no district for the province, remove the already prepared string "makeGeo.forValue(\"".$_SESSION["provincesresults"][$i][1]."\").addOptionsTextValue("
      if(substr($returnPD,-21) == "addOptionsTextValue);") {

         $returnPD = substr($returnPD, 0, -47);
      }

      //Set the Default Value
      $defaultP = "makeGeo.forValue(\"provinces\").setDefaultOptions(\"".$_SESSION["provincesresults"][$i][1]."\");";
   }               

   //Put Provinces, Districts, Communes and Villages together and close the Javascript
   $returnPDCV = $returnPD.$returnC.$returnV.$defaultD.$defaultC.$defaultV."</script>";

   //Return the result
   return sprintf($returnPDCV);
}
?>

In order to use the JavaScript, I use the following code in the patient_update.php:

//include the dynamic drop down generator
include("/functions/dyndrpdwn.php");

<!--Adding JavaScript for dynamic dropdown list-->
<script type=\"text/javascript\" src=\"/js/dynamicoptionlist.js\"></script>

//Call the dynamic drop down function
echo dyndrpdwn();

echo"<!--Province Create Drop-Down Field-->
     <select name=\"provinces\" class =\"dropdown\">";

//Fill the drop down, when data is received by get_value_help.php or if session array is already filled
if(isset($_GET["value"]) == "true" && $_GET["value"] == "receive" || isset($_SESSION["provincesresults"]) == "true" && count($_SESSION["provincesresults"]) > 0) {

   //Get all the values out of the Province array out of pdo.vhd

$countProvinces = count($_SESSION["provincesresults"]);

   for($i=0; $i < $countProvinces; $i++) {

      //Display the Khmer or the English language depending on the website settings. $_SESSION["searchresultspmd"][0][5]) = province_id in dbo.pmd 
      //$_SESSION["provincesresults"][$i][1] = province_id in dbo.vhp
      if(isset($_SESSION["lng"]) == "true") {

         switch ($_SESSION["lng"]) {

            case "english":  

               if($_SESSION["provincesresults"][$i][2] == $_SESSION["searchresultspmd"][0][5]) {

                  echo"<option value=".$_SESSION["provincesresults"][$i][1]." SELECTED>";
               }
               else {

                  echo"<option value=".$_SESSION["provincesresults"][$i][1].">";
               }

               echo"".$_SESSION["provincesresults"][$i][2]."
                  </option>";
               break;

            case "khmer":

               if($_SESSION["provincesresults"][$i][2] == $_SESSION["searchresultspmd"][0][5]) {

                  echo"<option value=".$_SESSION["provincesresults"][$i][1]." SELECTED>";
               }
               else {

                  echo"<option value=".$_SESSION["provincesresults"][$i][1].">";
               }

               echo"".$_SESSION["provincesresults"][$i][3]."
                  </option>";
               break;
         }
      }
   }
}

echo"          </select>
            </td>
            <td>

               <!--District Create Drop-Down Field-->
               <select name=\"districts\" class =\"dropdown\">
                  <script type=\"text/javascript\">
                     makeGeo.printOptions(\"districts\")
                  </script>
               </select>
            </td>
            <td>

               <!--Commune Create Drop-Down Field-->
               <select name=\"communes\" class =\"dropdown\">
                  <script type=\"text/javascript\">
                     makeGeo.printOptions(\"communes\")
                  </script>
               </select>
            </td>
            <td>

               <!--Village Create Drop-Down Field-->
               <select name=\"villages\" class =\"dropdown\">
                  <script type=\"text/javascript\">
                     makeGeo.printOptions(\"villages\")
                  </script>
               </select> 
            </td>

...

So there are two questions now:

  1. Calling the dyndrpdwn.php function takes quite a few seconds, as there are ~24 Provinces, ~86 Districts, ~1600 Communes and ~13500 Villages and I loop through them. Is there any way how to improve the performance?
  2. With setDefaultOptions I try to set the Default Value for the proper drop-down list. But in my code it does not work. I've compared it with the examples on [the JavaScript website][1] but I couldn't find the error... Can you see why it is not working the way I do it?

The result looks currently like that:

<script type="text/javascript">
var makeGeo = new DynamicOptionList("provinces","districts","communes","villages");

This creates the entries for provinces and districts:

makeGeo.forValue("010000").addOptionsTextValue("Mongkol Borei","010200","Phnum Srok","010300","Preah Netr Preah","010400","Ou Chrov","010500","Serei Saophoan","010600","Thma Puok","010700","Svay Chek","010800","Malai","010900");

This creates the entries for the communes

makeGeo.forValue("010000").forValue("010200").addOptionsTextValue("Banteay Neang","010201","Bat Trang","010202","Chamnaom","010203","Kouk Ballangk","010204","Koy Maeng","010205","Ou Prasat","010206","Phnum Touch","010207","Rohat Tuek","010208","Ruessei Kraok","010209","Sambuor","010210","Soea","010211","Srah Reang","010212","Ta Lam","010213");

This creates the entries for the villages:

makeGeo.forValue("010000").forValue("010200").forValue("010201").addOptionsTextValue("Ou Thum","01020101","Phnum","01020102","Banteay Neang","01020103","Kouk Pnov","01020104","Trang","01020105","Pongro","01020106","Kouk Tonloab","01020107","Trabaek","01020108","Khile","01020109","Samraong Pen","01020110","Dang Run Lech","01020111","Dang Run Kaeut","01020112","Ou Snguot","01020113","Prey Changha Lech","01020114","Prey Changha Kaeut","01020115","Ou Andoung Lech","01020116","Ou Andoung Kandal","01020117","Ou Andoung Kaeut","01020118","Kouk Kduoch","01020119");

And this should set the default value for the province, district and commune (just 3 examples; they don't work so far...):

makeGeo.forValue("240000").setDefaultOptions("Boeng Trakuon");
makeGeo.forValue("240200").setDefaultOptions("Ou Andoung");
makeGeo.forValue("240204").setDefaultOptions("Boeng Trakuon");</script>

<!--Province Create Drop-Down Field-->
<select name="provinces" class ="dropdown">
   <option value=010000>Banteay Mean Chey
   </option><option value=020000>Bat Dambang
   </option><option value=030000>Kampong Cham
   </option><option value=040000>Kampong Chhnang
   </option><option value=050000>Kampong Spueu
   </option><option value=060000>Kampong Thum
   </option><option value=070000>Kampot
   </option><option value=080000>Kandal
   </option><option value=090000>Kaoh Kong
   </option><option value=100000>Kracheh
   </option><option value=110000>Mondol Kiri
   </option><option value=120000>Phnom Penh
   </option><option value=130000>Preah Vihear
   </option><option value=140000>Prey Veaeng
   </option><option value=150000>Pousat
   </option><option value=160000>Rotanak Kiri
   </option><option value=170000>Siem Reab
   </option><option value=180000>Krong Preah Sihanouk
   </option><option value=190000>Stueng Traeng
   </option><option value=200000>Svay Rieng
   </option><option value=210000>Takaev
   </option><option value=220000>Otdar Mean Chey
   </option><option value=230000>Krong Kaeb
   </option><option value=240000 SELECTED>Krong Pailin
   </option></select>

   </td>
   <td>

      <!--District Create Drop-Down Field-->
      <select name="districts" class ="dropdown">
         <script type="text/javascript">
            makeGeo.printOptions("districts")
         </script>
      </select>
   </td>
   <td>

      <!--Commune Create Drop-Down Field-->
      <select name="communes" class ="dropdown">
         <script type="text/javascript">
            makeGeo.printOptions("communes")
         </script>
      </select>
   </td>
   <td>

      <!--Village Create Drop-Down Field-->
      <select name="villages" class ="dropdown">
         <script type="text/javascript">
            makeGeo.printOptions("villages")
         </script>
      </select> 
   </td>

I know its quite a lot of stuff to look through, sorry for that butevery help is highly appreciated!

1条回答
小情绪 Triste *
2楼-- · 2019-09-14 01:17

Unfortunately, the approach you outline above will not work. When you use php inside a javascript segment, you have to remember that the php code will be evaluated when the file containing the javascript is requested from the server only. Anything the PHP code has output during the request (e.g. via an 'echo' command) will then become part of your javascript function. In the case above, you have not output anything so your javascript code will essentially read .innerHTML=\" \"; once the page loads. Even if you did output data there, it would not be dynamic.

As I see it, you have 3 options:

  1. Use AJAX to load the HTML for the second drop down from a php file. This is definitely the way to go if you are already familiar with AJAX, but could be a bit tricky otherwise. If you aren't familiar, I would definitely recommend going through a few tutorials before trying to implement this option.

  2. Reload the page when the user changes the first drop down, and use a query string parameter to tell your PHP script what province has been selected. This is probably not a very good option, especially if this pair of drop downs is part of a larger form that the user might have already entered some data into.

  3. Have your PHP output the HTML for the first drop down, and then a separate drop down for each province that lists its respective districts. (So if you have 10 provinces, you would create 11 drop downs total.) Then you would use the CSS style display: none; to hide the secondary drop downs and use javascript to toggle their style to display: inline-block;. This option is not ideal for large numbers of options, because you are loading tons of potentially unnecessary data.

Out of curiosity, why are you storing the province data in the user's $_SESSION variable? I typically try to reserve that for user specific data or information pertaining to the state of the interface.

查看更多
登录 后发表回答