0

I'm using a library that takes, amongst other parameters, an array of names and create a <select> combobox containing the <option> elements named after what was in that array. It also assigns to the value attribute of the <option> nodes the value of the index at which the name was taken. So, for example, if the index 0 of an array contained "foo", then it would create a tag like follows: <option value="0">foo</option>. For reference, here is the code for that library:

function generateSelect(objDimensionAssoc, obj, select_name, label_name, function_name, state, DivAlignement)
{
    //Valid object before
    sChaine = "";
    if(  (obj != null) && (obj != undefined) && (obj != "") && (parseInt(countObject(obj)) > 0) ){
        if( state == 'show' ){

            sChaine +="<label for='"+select_name+"' ><span>"+label_name+"</span></label>\n";
            sChaine +="<div class='"+DivAlignement+"'>\n";
            if(function_name != "")
                sChaine +="<select name='"+select_name+"' id='"+select_name+"' onchange='"+function_name+"' >\n";
            else
                sChaine +="<select name='"+select_name+"' id='"+select_name+"'>\n";

            //lang = variable reconnu dans tout les pages

            for (var x=0; x < obj.length; x++){
                //One or two domentionnal array
                if(obj[x] != null){
                    if(objDimensionAssoc == "1"){
                        if(chaineUrl){
                            sChaine += compare_and_create( x, obj[x], chaineUrl[select_name], select_name);
                        } else {
                            sChaine += compare_and_create( x, obj[x], "", select_name);
                        }
                    } else { 
                        if(chaineUrl){  
                            sChaine += compare_and_create( x, obj[x][lang], chaineUrl[select_name], select_name);
                        } else {
                            sChaine += compare_and_create( x, obj[x][lang], "", select_name);
                        }
                    }
                }
            }

            sChaine +="</select>\n";
            sChaine +="</div>\n";

        }
        return(sChaine);
    } else {
        //empty array
        if( state == 'show' ){
            sChaine +="<label for='"+select_name+"' ><span>"+label_name+"</span></label>\n";
            sChaine +="<div class='"+DivAlignement+"'>\n";
            sChaine +="<select name='"+select_name+"' id='"+select_name+"' disabled='true' >\n";
            sChaine +="<option value='0'>&nbsp;</option>\n";
            sChaine +="</select>\n";
            sChaine +="</div>\n";
        }
        return(sChaine);
    }
}

function compare_and_create( key, innerText, string_compare,select_name)
{
    if(key == string_compare){
        return ("<option value='"+key+"' selected='selected'>"+innerText+"</option>\n");
    } else {
        return ("<option value='"+key+"'>"+innerText+"</option>\n");
    }
}

Here is where I call it:

myDiv = document.getElementById('tmp_stationDiv');
var stationsList = new Array();
stationsList = JSON.parse(<?php getStationList($regions); ?>);
myDiv.innerHTML = generateSelect("1",stationsList,
                            "slt_idStations",message["txt_choose_station"][lang],
                            '','show','blockDiv');

And this is the code of the function getStationList():

function getStationList($regions)
{
    $slt_nomStations = (isset($_GET["slt_nomStations"]) ? $_GET["slt_nomStations"] : 0);;
    $db = ConnectionFactory::getFactory()->getConnection();
    $stmt = $db->prepare("SELECT DISTINCT S.station_id, S.name, SA.sub_area_name FROM dev.Station AS S INNER JOIN dbo.SubArea AS SA ON S.sub_area_id = SA.sub_area_id INNER JOIN data.MonthlyNormalData as MND ON MND.station_id = S.station_id WHERE sub_area_name = '$regions[$slt_nomStations]' AND value IS NOT NULL ORDER BY S.name ASC");
    $stmt->execute();

    $stations = array();
    $lastStationName = "";
    while ($row = $stmt->fetch())
    {
        if ($lastStationName != $row['name'])
        {
            array_push($stations, $row['name']);
            $lastStationName = $row['name'];
        }
    }

    $newJSArray = json_encode($stations);
    echo json_encode($newJSArray);
}

Now this works perfectly fine. The output of getStationList() is, for example, "[\"LA GRANDE RIVIERE A\"]" and I then use JSON.parse() to transform that into a javascript array.

Unfortunately, the value associated with the <option> node will be 0, 1, 2, ..., n, where n is the number of stations - 1. I would like to associate the name of the stations with their station ID (which I recover from the database) so the value associated with the <option> node would be those IDs. To do that, I suppose I would need to push the name of the stations at the index of the corresponding ID. I have tried doing that with the following modifications to getStationList():

function getStationList($regions)
{
    $slt_nomStations = (isset($_GET["slt_nomStations"]) ? $_GET["slt_nomStations"] : 0);;
    $db = ConnectionFactory::getFactory()->getConnection();
    $stmt = $db->prepare("SELECT DISTINCT S.station_id, S.name, SA.sub_area_name FROM dev.Station AS S INNER JOIN dbo.SubArea AS SA ON S.sub_area_id = SA.sub_area_id INNER JOIN data.MonthlyNormalData as MND ON MND.station_id = S.station_id WHERE sub_area_name = '$regions[$slt_nomStations]' AND value IS NOT NULL ORDER BY S.name ASC");
    $stmt->execute();

    $IDs = array();
    $names = array();
    $stations = array();
    $lastStationName = "";
    while ($row = $stmt->fetch())
    {
        if ($lastStationName != $row['name'])
        {
            array_push($names, $row['name']);
            array_push($IDs, $row['station_id']);

            $lastStationName = $row['name'];
        }
    }

    $stations = array_fill_keys($IDs, $names);

    $newJSArray = json_encode($stations);
    echo json_encode($newJSArray);
}

Unfortunately, this does not work since the output of the getStationList() function is now something like this: "{\"6047\":[\"LA GRANDE RIVIERE A\"]}". So how would I have to modify my code for it to generate my <select> node with its children <option> nodes having their value attribute set to the ID of each of their corresponding station names?

3
  • Don't call json_encode() on the result of calling json_encode. Commented Jul 30, 2014 at 17:02
  • @Barmar If I don't, I get the following error: SyntaxError: JSON.parse: unexpected character, which is at the following line: stationsList = JSON.parse({"6047":"LA GRANDE RIVIERE A"});. Not calling json_encode() a second on the result of called json_encode()' makes the output of the function getStationList()` {"6047":"LA GRANDE RIVIERE A"} instead of "{\"6047\":[\"LA GRANDE RIVIERE A\"]}" Commented Jul 30, 2014 at 17:08
  • 1
    Ahh, that's because you're calling JSON.parse() unnecessarily in the Javascript. Inserting the result of getStationList() parses it automatically, and then you parse it again. Get rid of both these extra encodes and parses. Commented Jul 30, 2014 at 17:09

1 Answer 1

1

Why not something like

$arr = array()
while ($row = $stmt->fetch()) {
     $arr[$row['stationID']] = $row['stationName'];
}

You're using array_push, which doesn't let you specify a key for the pushed value - you'll just get the next higher available index. So don't use the array_*() functions, and just stuff in your key/value pairs directly.

Sign up to request clarification or add additional context in comments.

5 Comments

I just tried this solution, and it outputs the same "{\"6047\":[\"LA GRANDE RIVIERE A\"]}" as the way I have done it initially. When I debug the code, the problem seems to be at for (var x=0; x < obj.length; x++) where it does not go in that for to create the <option> nodes (my combobox is empty).
you can't use a for loop if your keys aren't sequential. you need a for (var i in arr) loop
It now works when I modified for (var x=0; x < obj.length; x++) for for (var x in obj), unfortunately now I am stuck with extra <option> nodes in all of my <select> comboboxes that contain function names as value attribute and the function implementation between the <option> and </option> tags. Is there a way to get rid of them? This seems to be caused because the for goes and get the values in the _proto_ as well as in the "regular" indexes of the array (found that out while debugging).
If it can help, the comboboxes that are displaying this behavior are of type [object Array], while the one that is ok (the station combobox which I tried your solution on) is of type [object Object] in the debugger.
a jquery $.each() may be better then, it knows to skip "internal" things.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.