This is a problem (or design pattern?) which I would think is pretty common, so I hope this post might help others with a similar problem....
I have the not uncommon situation where a complex form needs to dynamically allow users to edit data that depends on other choices the user makes. I'm using Ajax, jQuery with PHP and postgres as the backend database.
I have figured out how to return the data for a single record, based on two values picked by the user, using a jQuery Ajax technique (Ajax is sooo much slicker than php for this); usually the return value will be one record, which my HTML form can handle. But sometimes the return value will be two or three records. In that case, I need to dynamically add input fields and populate them with the returned data.
Here is the code in my form; the Fetch button takes the Selected Marker value and the Selected LabID value to lookup the dependant record, which contains Allele_1, Allele_2 and Run date:
<fieldset>
<LEGEND><b>Edit Genotype</b></LEGEND>
<p>
<boldlabel>Selected Marker</boldlabel><input name=sel_marker length=15 DISABLED>
<boldlabel>Selected LabID</boldlabel><input name=sel_labid length=10 DISABLED><br>
<boldlabel>Allele_1</boldlabel><input id=allele1 name=allele_1 size=5 >
<boldlabel>Allele_2</boldlabel><input id=allele2 name=allele_2 size=5 >
<boldlabel>Run date</boldlabel><input id=run_date name=run_date size=10 >
<br>
</p>
<input type="button" name="fetch" id="fetchbutton" value="Fetch" sclass="btn">
<input type="button" name="save" value="Save" onclick="savegenotype()" class="btn">
<br>
</fieldset>
This is the javascript code linked to Fetch button:
function fetchgenotype() {
// here's where we use an Ajax function to fetch the allele values without reloading the page.
// Get the index number of the genotype record to retrieve; retrieve it; populate the alleles.
var mndx = document.EditGenotype.marker.options[document.EditGenotype.marker.selectedIndex].value;
var sndx = document.EditGenotype.labid.options[document.EditGenotype.labid.selectedIndex].value;
$.post("fetchAlleles.php", {mndx: mndx, sndx: sndx},
function(result) {
i=0;
result.each(
a1='allele1_'||i.toString();
a2='allele2_'||i.toString();
r='rundate_'||i.toString();
$("#run_date").after(a1);
$("#run_date").after(a2);
$("#run_date").after(r);
)
}, "json");
return false;
}
Here is the separate PHP script that is the Ajax part that looks up the related data:
// query the database.
$dbconnect = pg_pconnect("host=".$hostname." user=".$dbuser." dbname=".$dbname);
if (!$dbconnect) {
showerror(0,"Failed to connect to database",'fetchAlleles',16,"username=".$dbuser.", dbname=".$dbname);
exit;
}
$sql = "SELECT allele1, allele2, run_date FROM geno.genotypes WHERE markers_id=".$mndx." AND gsamples_id=".$sndx;
$fetchresult = pg_exec($dbconnect, $sql);
if ($fetchresult) {
$arr = pg_fetch_array($fetchresult, 0, PGSQL_NUM);
// for debugging
//print_r($arr);
} else {
echo "(25) Failed to retrieve results.<BR>SQL: ".$sql."</br>";
}
// It appears necessary to return the array as json encapsulated.
echo json_encode($arr);
?>
}
This part works, I know, for the single value case; but when the return value is an array of multiple records, my jQuery code in my javascript section of my form has incorrect syntax. I get an error in the line a1='allele1_'||i.toString();
Any jQuery gurus who can set me straight would be much appreciated...
My first thought: use pg_affected_rows to find out whethaer you got one or more records.
My second thought: why not pg_fetch_object ? I think you'll get much better (readable) json.
My third thought : you should unify the JSON output. Pretty common practice is - JSON response should look like an Array of Objects. If DB return only one record -> JSON-response is an Array with ONLY item in it. If DB returns more than one -> JSON-response is an Array with more than one items in it
Example of JSON-Response
//DB return only ONE record
{
"items": [
{
"allele1" : "the-value",
"allele2" : "the-value",
"run_date" : "the-date"
}
],
"totalItems : 1
}
//DB returns more than one records
{
"items": [
{
"allele1" : "the-value_1",
"allele2" : "the-value_1",
"run_date" : "the-date_1"
},
{
"allele1" : "the-value_2",
"allele2" : "the-value_2",
"run_date" : "the-date_2"
},
...
{
"allele1" : "the-value_n",
"allele2" : "the-value_n",
"run_date" : "the-date_n"
}
],
"totalItems : n
}
If you get result like this, you can easier create INPUT-field dynamically. First of all, you can easy check if you recieved one or more records
if(response.totalItems === 1 ) {
// handle single record
}else if (response.totalItems > 1) {
// handle multiple records
}
in case of multiple records, you can iterate through with jQuery.each() & jQuery.map() and generate inputfields
if (response.totalItems > 0) {
//iterate through all items in JSON-response
$.each(response.items, function(index, object) {
// create FIELDSET element
var $fieldset = $('<fieldset>', {'html' : '<legend>#'+(index+1)+'</legend>'});
$.map(object, function(value ,key) {
//create LABEL element and appendInto FIELDSET
$fieldset.append($('<label>', {'text' : key, 'for' : key}));
//create INPUT element and appendInto FIELDSET
$fieldset.append($('<input>', {'id': key, 'name': key, 'value' : value}));
//create LineBreak
$fieldset.append('<br />');
});
// Append whole FIELDSET with LABEL, INPUT and BR to body (or whatever your placeholder is)
$('body').append($fieldset);
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With