Fetch hidden product_id from database to jquery autocomplete plugin list - php

I am using jquery autocomplete plugin for selecting data from database using PHP, MySql and Ajax.
The plugin operates good except fetching the product_id. When the plugin fetches the autocomplete list I want also to attach a hidden product_id to the products to differentiate the products for example in case of multiple products with the same product_name.
Below is the code that functions only with product_name.
function select_name(){
$("[id^='product_name']").focus(function() {
var id = $(this).attr('id');
id = id.replace("product_name",'');
$("[id^='product_name']").autocomplete({
source: 'store_supply/fetch_autocomplete_name.php',
select: function (event, ui) {
var pro_nm = ui.item.value;
$.ajax({
url:"store_supply_manage/fetch_product_code.php",
method:"POST",
data:{pro_nm:pro_nm},
//here I want to post a product_id when selecting the product_name
dataType:"json",
success:function(data){
$('#mu_emri_'+id).val(data.mu_name);
$('#product_code_'+id).val(data.barCode);
$('#vat_vlera_'+id).val(data.vat_value_4);
$('#product_id'+id).val(data.product_id);
calculateTotal();
}
});
}
});
});
}
//fetch_autocomplete.php
if (isset($_GET['term'])) {
$term = $_GET['term'];
$query = $db->prepare("SELECT product_name FROM products
WHERE product_name LIKE '%$term%' LIMIT 10");
$query->execute();
$nr = $query->rowCount();
if ($nr > 0) {
while ($row = $query->fetch()) {
$result[] = $row['product_name'];
}
}
else {
$result = array();
}
//return json result
echo json_encode($result);
}

In your code you are preparing your SQL statement but interpolating the $term variable instead of parameterizing your query. In the example below I have parameterized your query.
As shown in the documentation, the data can be either:
An array of strings: [ "Choice1", "Choice2" ]
An array of objects with label and value properties: [ { label: "Choice1", value: "value1" }, ... ]
So you can just change your fetch_autocomplete.php to something like:
if (isset($_GET['term'])) {
$term = '%' . $_GET['term'] . '%';
// parameterized query in nowdoc*
$sql = <<<'SQL'
SELECT id AS `value`, product_name AS `label`
FROM products
WHERE product_name LIKE :term
LIMIT 10
SQL;
// prepare the query
$query = $db->prepare($sql);
// bind variables and execute
$query->execute(['term'] => $term);
// As fetchAll() returns an empty array if there are no matching
// rows we do not need to check rows returned
$result = $query->fetchAll(PDO::FETCH_OBJ);
// return json result
echo json_encode($result);
}
* nowdoc
Change id to whatever the name of your product id column is. Now, inside your select handler, ui.item.value will be the product id instead of its name.

Related

How to retrieve multiple data from ajax post function?

I have a select dropdown list and some input fields. My goal is when I select any option from the dropdown list it takes it's value and insert it into the input fields, and that is the ajax post function
<script>
$(document).ready(function(){
$('#productSelect').on('change',function(){
var selectedValue = $('#productSelect').val();
$.post('php/loadProducts.php', {
productId : selectedValue
}, function(data, status) {
$('#id').val(data);
$('#name').val(data);
$('#price').val(data);
});
});
});
</script>
and that is what happens in the "loadProdcut.php" file
<?php
if (isset($_POST['productId'])) {
$productId = $_POST['productId'];
$sql = "SELECT * FROM products WHERE product_id = '$productId';";
$result = mysqli_query($conn, $sql);
$resultCheck = mysqli_num_rows($result);
if ($resultCheck > 0) {
while ($row = mysqli_fetch_assoc($result)) {
$Id = $row['product_id'];
echo $Id;
$Name = $row['product_name'];
echo $Name;
$Price = $row['product_price'];
echo $Price;
}
};
}
?>
Now when I select any option of the dropdown list it inserts all the values (id, name and price) in every single input field, so what I want to achieve is to place every single value into it's input feild.
It's simpler and more reliable to return JSON from an AJAX call to the server if for no other reason than you then return it all in one lump rather than in multiple echo's
Also a prepared statement protects you from bad actors attempting to mess up your database.
I am assuming as you are using a product_id to access a product table there will be only one row returned, so the loop is unnecessary
<?php
if (isset($_POST['productId'])) {
// query with prameter ?
$sql = "SELECT product_id, product_name, product_price
FROM products WHERE product_id = ?";
// prepare it
$stmt = $conn->prepare($sql):
// bind the parameter to its data
$stmt->bind_values('i', $_POST['productId']);
$stmt->execute();
// get resultset from the execution of the query
$result = $stmt->get_result();
$row = $result->fetch_assoc();
//return the row (an array) converted to a JSON String
echo json_encode($row);
}
Now you need to amend the javascript to process the nice object you have just returned.
<script>
$(document).ready(function(){
$('#productSelect').on('change',function(){
var selectedValue = $('#productSelect').val();
$.post('php/loadProducts.php', {productId : selectedValue}, function(data, status) {
$('#id').val(data.product_id);
$('#name').val(data.product_name);
$('#price').val(data.product_price);
});
});
});
</script>

PHP - Create XML from multiple MySQL queries and sort by date

I have 10-20 log-tables in a MySQL database. Each table contains 50-100.000 rows. I need to export these to XML and sort them by creation date.
Union is a good option as the tables doesn't contain the same columns (one table might contain 3 column, and another 30 columns).
This is how I create the XML:
// Events
$stmt = $db->query("
SELECT id, columnX, created
FROM table1
");
$row_count = $stmt->rowCount();
if ($row_count != '0') {
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$event = $xml->createElement("event");
$events->appendChild($event);
$event->appendChild($xml->createElement("ID", "XXXX"));
$event->appendChild($xml->createElement("columnX", $row['columnX']));
$event->appendChild($xml->createElement("created", $row['created']));
}
}
// Other events
$stmt = $db->query("
SELECT id, columnY1, columnY2, columnY3, created
FROM table2
");
$row_count = $stmt->rowCount();
if ($row_count != '0') {
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$event = $xml->createElement("event");
$events->appendChild($event);
$event->appendChild($xml->createElement("ID", "XXXX"));
$event->appendChild($xml->createElement("columnY1", $row['columnY1']));
$event->appendChild($xml->createElement("columnY2", $row['columnY2']));
$event->appendChild($xml->createElement("columnY3", $row['columnY3']));
$event->appendChild($xml->createElement("created", $row['created']));
}
}
Anyone got an idea of how to solve this?
I suggest using an INSERT INTO ... SELECT ... UNION ... SELECT construct to fetch all the data into a (temporary) table. INSERT INTO ... SELECT allows you to directly insert the result of an select into a table. UNION allows you to concat SELECT results. Because it is a database statement it all happens in the DBMS.
After that use a select to fetch the data ordered by date field and use XMLWriter to create the XML.
If there is possibility to sort all queries, you are able to sort final XML by getting all queries from database and then printing out them like in code bellow.
Be aware, that this code WILL probably consume as much memory as data returned by all queries in one time, because you cannot use unbuffered query in this case. I don't know, how big are datasets, you are talking about.
If memory would be your concern, you can use same algorithm to combine any data source. So you can prepare three XML files (per query) and combine these instead of combining SQL. It would be (in combination with mysql unbuffered queries) probably better variant for memory usage, but slower as you will need generate and parse XML.
// convert queries to generator
function processQuery(mysqli $db, $sql) {
$q = $db -> query($sql);
while ($row = $q -> fetch_assoc()) {
// just yield
yield $row;
}
}
// prepare all queries
$queries = [
processQuery($db, "SELECT id, columnX, created FROM table1 ORDER BY created"),
processQuery($db, "SELECT id, columnY1, columnY2, columnY3, created FROM table2 ORDER BY created"),
processQuery($db, "SELECT id, created FROM table3 ORDER BY created"),
];
// run all queries and fetch first row
foreach ($queries as $query) {
$query -> next(); // see \Generator
}
// now, we will run while any query has rows (generator returns key)
while (array_filter(array_map(function(Generator $query) { return $query -> key(); }, $queries))) {
// now we have to find query, which next row has minimal date
$minTimestamp = NULL;
$queryWithMin = NULL;
foreach ($queries as $queryId => $query) {
$current = $query -> current();
if ($current !== FALSE) {
if ($minTimestamp === NULL || $minTimestamp > $current['created']) {
// this query has row with lower date than previous queries
$minTimestamp = $current['created'];
$queryWithMin = $queryId;
}
}
}
// we now know, which query returns row with minimal date
PRINT_TO_XML($queries[$queryWithMin] -> current());
// move cursor of this query to next row
$queries[$queryWithMin] -> next();
}
Another aproach could be MySQL UNION only for getting ids (already sorted) and then process them in batches.
$q = $db -> query("SELECT 'table1' AS tableName, id, created FROM table1
UNION ALL SELECT 'table2' AS tableName, id, created FROM table2
UNION ALL SELECT 'table3' AS tableName, id, created FROM table3
ORDER BY created");
$sorter = [];
while ($row = $q -> fetch_assoc()) {
$sorter []= [$row['tableName'], $row['id']];
}
foreach (array_chunk($sorter, 5000) as $dataChunk) {
// get ids from each table
$table1Ids = array_map(function($rowInfo) { return $rowInfo[1]; }, array_filter($dataChunk, function($rowInfo) { return $rowInfo[0] === 'table1'; }));
$table2Ids = array_map(function($rowInfo) { return $rowInfo[1]; }, array_filter($dataChunk, function($rowInfo) { return $rowInfo[0] === 'table2'; }));
$table3Ids = array_map(function($rowInfo) { return $rowInfo[1]; }, array_filter($dataChunk, function($rowInfo) { return $rowInfo[0] === 'table3'; }));
// load full data from each table
$dataTable1 = [];
$q = $db -> query("SELECT * FROM table1 WHERE id IN (".implode(",", $table1Ids).")");
while ($row = $q -> fetch_assoc()) {
$dataTable1[$row['id']] = CREATE_XML($row);
}
// ... same with table2
// ... same with table3
// store
foreach ($dataChunk as $row) {
if ($row[0] === 'table1') {
echo $dataTable1[$row[1]];
}
if ($row[1] === 'table1') {
echo $dataTable2[$row[1]];
}
if ($row[2] === 'table1') {
echo $dataTable3[$row[1]];
}
}
}
This approach is less memory consuming, but in this exact code, you will need to load all IDs to memory first. It's possible to simple rewrite to generate XML in first loop (if count($sorter) > 5000 { printXmlForIds($sorter); $sorter = []; }) and algorithm would not exceed memory limt.

Why can't I access textarea id's after parsing array

I'm loading multiple clients on a page, each record with its own <textarea>. I set each <textarea> with the client's clientid.
if(isset($_POST['loaddata'])){
try{
$stmt = $db->prepare('SELECT clientid, fname, lname
FROM clients
WHERE memberid = :memberid
AND groupid = :groupid
ORDER BY lname');
$stmt->bindValue(':memberid', $_SESSION["memberid"], PDO::PARAM_INT);
$stmt->bindValue(':groupid', $_POST['groupid'], PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetchAll();
foreach($result as $row ) { $i++;
echo '<tr style="'.getbgc($i).'">
<td style="display:none">'.$row[0].'</td>
<td style="width:auto;">'.$row[1].'</td>
<td style="width:auto;">'.$row[2].'</td>
<td><textarea id='.$row[0].' class="form-control" rows="1"></textarea></td>
</tr>';
}
} ...
After the data loads, I test the <textarea> id's:
$.ajax({
url : 'wsparticipation.php',
type : 'POST',
async : false,
data : {
'loaddata' : 1,
'groupid' : temp
},
success:function(re){
$('#showdata').html(re);
$('#13').html("I am 13");
$('#15').html("I am 15");
$('#10').html("I am 10");
} ...
and the textareas show the html.
When I get ready to save the the entered data, I set the clientid's into an array.
if(isset($_POST['getarray'])){
$stmt = $db->prepare('SELECT clientid
FROM clients
WHERE memberid = :memberid
AND groupid = :groupid
ORDER BY lname');
$stmt->bindValue(':memberid', $_SESSION["memberid"], PDO::PARAM_INT);
$stmt->bindValue(':groupid', $_POST['groupid'], PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetchAll();
$ret = array();
foreach($result as $row ) {
$ret[] = $row['clientid'];
}
echo json_encode($ret);
exit();
}
$.ajax({
url : 'wsparticipation.php',
type : 'POST',
datatype : 'JSON',
data : {
'getarray' : 1,
'groupid' : temp
},
success:function(re){
data = $.parseJSON(re);
$.each(data, function(i, clientid) {
alert(clientid);
$('#clientid').html("hahaha");
});
$('#2').html("Made it here with this");
}
});
The alert() indeed shows me each of the clientid's, but the next statement $('#clientid').html("hahaha"); does nothing. The last statement $('#2').html("Made it here with this"); puts that text in the appropriate textarea.
So, since the alerts are showing me the clientid's, why am I not able to access the textarea using the clientid from $.each(data, function(i, clientid)?
$('#clientid') selects an element with the ID of "clientid".
I think you want to dynamically build the selector by concatenating the "#" symbol with your variable's value:
$('#'+clientid).html("hahaha");
Example below:
var clientid = 2;
$('#' + clientid).html('test');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea id="2"></textarea>
Change your selector from:
$('#clientid').html("hahaha");
to
$('#'+clientid).html("hahaha");
Also a side note: Don't use integers as ids, it's very bad idea and it's not really descriptive of what it is, a better choice might be: clientInfo1, clientInfo2.. etc or clientTextarea1, clientTextarea2 .. etc

Retrive an array stored in database using PDO

I have an array: productid = [1,2]. Now I want to fetch data from product table by using this part of code:
$sql = 'SELECT name FROM product WHERE id=:id';
$s = $pdo->prepare($sql);
foreach($productid as $id)
{
$s->bindValue(':id', $id);
$s->execute();
}
when I returned the names as follow:
foreach($s as $row)
{
$name[] = array(
'name' => $row['name']
);
}
I just got the product name of second id and didn't get both names.
What's the problem?
I just got the product name of second id and didn't get both names. What's the problem?
You've got to put your $name[] = $row['name']; (yes, that's right notation) code inside of the foreach loop, as well as code that actually fetches the data.
You may also form a IN() statement that should be looks like IN (?,?,?,?) and run it in one query. Something like this (not tested):
$in = trim(str_repeat('?,',count($productid)).",");
$sql = "SELECT name FROM product WHERE id IN ($id)";
$stmt = $db->prepare($sql);
$stmt->execute($productid);
$name = $stmt->fetchAll();

PHP/jQuery AJAX algorithm only working every other time

I am trying to build a page that uses jQuery to call a database every second and return the highest numbered row.
The jQuery code is below (this is in $('document').ready)
var id = 0;
$.post('check.php', 'id=0', function(data){
id = parseInt(data);
$('h1').text(data);
});
var timer = setInterval(function() {
$.post('check.php', 'id=' + id, function(data){
if (data != '')
$('h1').text(data)
else
$('h1').text("NOTHING!");
id = parseInt(data);
});
}, 1000);
And the PHP file, check.php, has the following code (after connecting to the database):
$id = $_POST['id'] - 1;
$query = "SELECT * FROM testtable WHERE 'id' > $id ORDER BY id DESC";
$result = mysql_query($query);
$row = mysql_fetch_row($result);
echo "$row[0]";
When 'id' is the first column.
The highest row number right now is 13. I would expect it to send 13 to the PHP file. $id would then be 12, so it would select all rows with id values higher than 12, returning the row with id value 13. Then it would echo "13", which is sent back to jQuery, which is parsed to an integer, making id equal to 13. Then 13 is sent to the PHP file again a minute later, and the process cycles.
What's actually happening is that it's alternating between displaying "13" and "NOTHING!", and I can't figure out why.
Because select * from tesstable where id > 13 will always be an empty result if 13 is the highest id. What you want is this:
select max(id) as id from testtable
You don't have to send back $id, and if it's got an index on it, this query will return very quickly.
Also, your original query has the column id in quotes, not backticks. You're comparing the string "id" with your variable $id. To top that off, you're susceptible to SQL injection here, so use mysql_escape_string, PDO, or remove the variable reference altogether using the max query provided.
I'll suggest you to do it like this.Try it.And tell if it's working.
var id = 0,count = 0;
$.post('check.php', {id:0}, function(data){
id = +data["rows"]; // Try parse or just a +
$('h1').text(data);
count++;
},"json");
var timer = setInterval(function() {
$.post('check.php', {id:id-count}, function(data){
if (data["rows"] != null || data["rows"] != "")
$('h1').text(data)
else
$('h1').text("NOTHING!");
id = +data["rows"];
count++;
},"json");
}, 1000);
$id = $_POST['id'];
$queryString = ($id == 0) ? "'id' > $id" : "'id' = $id";
$query = "SELECT * FROM testtable WHERE $queryString ORDER BY id DESC";
$result = mysql_query($query);
$row = mysql_fetch_row($result);
echo json_encode(array("rows" => "$row[0]");

Categories