MySQL / PHP / JS динамически заполненное выпадающее меню - PullRequest
1 голос
/ 03 августа 2011

Я работаю над интерфейсом DB / web и столкнулся с проблемой.Прежде всего, у меня есть форма с выпадающим меню, содержащим список контрактов.После выбора контракта я бы хотел, чтобы задания, связанные с этим контрактом (извлеченные из БД MySQL), заполняли второе раскрывающееся меню под первым.

Я бы просто получил всю информацию водно меню, но выпадающее меню ввода 8000 немного громоздко.

Мой PHP и HTML едва проходимы, но этого достаточно для моих целей, однако мой опыт работы с ECMA ограничен немного ActionScript во Flash MXмного лун назад.Я хотел бы по возможности избегать использования сторонних библиотек JS (таких как jQuery), и я не против написать больше кода.Мне просто нужно знать, выполнимо ли это, и немного подтолкнуть в правильном направлении.

Я замолчу сейчас, вот форма для получения идентификатора контракта (и связанного клиента), а также неполныйменю задания.

<select name='idcontract' onchange=''> 
<!--fetch/display contracts/clients-->
    <?php
        include 'sqldb.php';
        $cntqres = mysqli_query($dbc, 'SELECT * FROM contract');
        while ($cntrow = mysqli_fetch_array($cntqres))
        {
            $cliqres = mysqli_query($dbc, "SELECT * FROM client WHERE idclient = '$cntrow[idclient]'");
            while ($clirow = mysqli_fetch_array($cliqres))
            {
                echo "<option value='$cntrow[idcontract]'>$cntrow[idcontract] $clirow[name]</option>";
            }
        }
    ?>
</select>
<select name='idjob'>
    <option value='NULL'>Please select a contract</option>
<!--here goes the magical piece of code I don't know how to write-->
</select>

Любая помощь будет принята с благодарностью.

Редактировать:

Вот PHP, вызываемый FeatherAJAX :

<?php
    include 'sqldb.php';
    $cnt = mysqli_real_escape_string($dbc, $_GET['cnt']);
    $sql = "SELECT * FROM job WHERE idcontract='$cnt' ORDER BY job.idjob";
    $jqres = mysqli_query($dbc, $sql);
    $i = 1;
    while (($jrow = mysqli_fetch_array($jqres)) && ($i < count($jrow)))
    {
        echo "idjob=><option value='$jrow[idjob]' id='$jrow[idjob]'>Job-$i $jrow[part_desc]</option>";
        $i++;
    }
?>

1 Ответ

2 голосов
/ 03 августа 2011

Во-первых, вы можете переписать кусок кода, который создает параметры контракта. Циклический просмотр результатов запроса и выполнение другого запроса для каждой записи неэффективно. Основываясь на ваших запросах, вы можете использовать этот код, который выполняет один запрос, а затем генерирует параметры на основе этого. (Я должен был использовать имена составных столбцов в предложении ORDER. В общем, вы всегда должны сортировать набор записей так, чтобы результаты были в определенном порядке - даже если вам все равно, каков этот порядок.

<select name="idcontract" id="idcontract"> 
<!--fetch/display contracts/clients-->
<?php
include 'sqldb.php';
$clients = mysqli_query($dbc, '         
    SELECT  ct.idcontract, ct.idclient, cl.name
    FROM    contract ct LEFT OUTER JOIN client cl ON ct.idclient = cl.idclient
    ORDER BY ct.contractname, cl.clientname
    ');

while ($client = mysqli_fetch_array($clients)) {
    echo "<option value=\"{$client[idcontract]}\">{$client[idcontract} {$client[name]}</option>";
}
?>
</select>
<select name="idjob" id="idjob">
    <option value="NULL">Please select a contract</option>
</select>

На ваш вопрос, код, который вы ищете, на самом деле не идет туда, где находится этот комментарий. Вам нужен обработчик событий, который отвечает на выбор пользователем опции в первом SELECT; Затем он должен получить значение этой опции и запросить у сервера набор пар ключ-значение для вставки во второй SELECT.

Примерно так:

document.getElementById('idcontract').onchange = function(event) {
    // grab currently selected value
    var sValue = null;
    for(var i = 0, imax = this.childNodes.length; i < imax; i++) {
        var eOption = this.childNodes[i]; // shorthand
        if(eOption.selected) {
            sValue = eOption.value;
            break;
        }
    }

    if(!sValue) return;

    // get the sub-options for this value
    getSubOptions(sValue, function(XHR) {
        // this code runs once the response comes back from the server
        var aPairs = [];
        var nlJobs = XHR.getElementsByTagName('jobs'); // assumptions #1 & #2: response is XML, includes <job> tag for each job

        // extract key-value pairs from XML
        for(var i = 0, imax = nlJobs.length; i < imax; i++) {
            var xJob = nlJobs[i]; // shorthand
            /*
                assumption #3: <job> tag has "id" property
                assumption #4: job name appears inside <job> tag
                assumption #4.5: you've got an abstraction layer that normalizes XML node interfaces so that "text" and "textContent" are folded into "textContent"
            */
            aPairs.push({ 'key': xJob.getAttribute('id'), 'value': xJob.textContent });
        }

        // given array of key-value pairs, rebuild select box
        var eJobs = document.getElementById('idjob');

        setOptions(eJobs, aPairs);
    });
}

function setOptions(eNode, aPairs) {
    if(!eNode || !eNode.nodeName || eNode.nodeName.toUpperCase() !== 'SELECT') return false;

    // empty SELECT of all options
    while(eNode.firstChild) {
        eNode.removeChild(eNode.firstChild);
    }

    // build up new nodes
    var eOpt = null;
    for(var i = 0, imax = aPairs.length; i < imax; i++) {
        eOpt = document.createElement('OPTION');
        eOpt.value = aPairs[i].key;
        eOpt.appendChild(document.createTextNode(aPairs[i].value));
        eNode.appendChild(eOpt);
    }
    return true;
}

Конечно, здесь не хватает важной части: вам нужен какой-то слой абстракции AJAX. Вам не нужно получать это из фреймворка, и хорошая библиотека для этого может содержать менее 50 строк кода (например, см. Ajax-скрипт PPK на quirksmode.org), но вам что-то абсолютно необходимо. Этот уровень обеспечит два преимущества: (1) кросс-браузерная совместимость; (2) синтаксический сахар.

Например, приведенный выше код не включает определение getSubOptions. Это связано с тем, что логика будет зависеть от интерфейса, предоставляемого вашей абстракцией AJAX. Идея, однако, заключается в том, что вы будете выполнять запрос GET к написанному вами сценарию, который принимает аргументы и возвращает данные, удовлетворяющие этому запросу. В приведенном выше коде я сделал вид, что сценарий, который вы пишете, будет возвращать правильно сформированные данные XML с типом MIME, идентифицирующим их как таковой. В качестве альтернативы вы можете использовать JSON (или JSONP), прямой текст (например, данные в стиле CSV) или даже необработанный HTML, который вы просто вставите на страницу.

Преимущество использования полной структуры состоит в том, что все они предоставляют удобные способы выполнения DOM-манипуляций (т.е. снова синтаксический сахар).

Суть: вы можете сделать это с помощью доморощенного подхода (и я с гордостью могу сказать, что сделал это сам). Но это займет больше времени - не только потому, что это менее удобно, но и потому, что вам придется заново изобретать колесо === для поиска и исправления ошибок в вашем коде вместо того, чтобы использовать проверенные основные компоненты из некоторой библиотеки.

РЕДАКТИРОВАТЬ: Если вы хотите использовать JSON в качестве формата обмена данными вместо XML, вы бы изменили обработчик ответа, передаваемый в getSubOptions, примерно так:

getSubOptions(sValue, function(XHR) {
     // this code runs once the response comes back from the server
    var aPairs = eval(XHR.responseText); // assumes JSON defines an array of key-value pairs

    // given array of key-value pairs, rebuild select box
    var eJobs = document.getElementById('idjob');

    setOptions(eJobs, aPairs);
});

А вот пример того, как может выглядеть этот JSON:

[ { key: '1234', value: 'Job #1' },
  { key: '2345', value: 'Job #2' },
  ...
];

В этом примере структура JSON удобно отражает имена свойств, ожидаемые setOptions; тем не менее, key и value кажутся довольно безобидными.

Если вы настроили использовать JSON для данных, вы можете рассмотреть JSONP как более безопасную альтернативу. Это действительно похоже, но шаблон дизайна немного отличается от описанной выше техники анонимного обратного вызова.

РЕДАКТИРОВАТЬ 2: Модифицированный пример кода для респондента:

<?php
include 'sqldb.php';
$cnt = mysqli_real_escape_string($dbc, $_GET['cnt']);
$sql = "SELECT * FROM job WHERE idcontract='$cnt' ORDER BY job.idjob";
$jqres = mysqli_query($dbc, $sql);
$i = 1;

// prepare the response
header('Content-Type: text/html');

while (($jrow = mysqli_fetch_array($jqres)) && ($i < count($jrow))) {
    echo "<option value=\"$jrow[idjob]\" id=\"$jrow[idjob]\">Job-$i ${htmlentities(jrow[part_desc])}</option>";
    $i++;
}
?>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...