This is a .php file that creates a table.
<table id="contact-messages">
<thead>
<tr>
<th>Username</th><th>Category</th><th>Message</th><th>Created at</th>
</tr>
</thead>
<tbody>
<?php
foreach ($contact_messages as $message) {
echo '<tr>'
. '<td>' . htmlentities($message['username']) . '</td>'
. '<td>' . htmlentities(ucfirst($message['category'])) . '</td>'
. '<td>' . nl2br(htmlentities($message['message'])) . '</td>'
. '<td class="created-at" data-created_at="' . htmlentities($message['created_at']) . '"></td>'
. '</tr>';
}
?>
</tbody>
</table>
And this is the .js file for that page. This code changes the content of the table.
$.get("contact-messages.php", { "category": category }, function (data) {
$("#contact-messages").find("tbody").empty(); // Empty the old messages.
for (var i = 0; i < data.length; i++) {
$("#contact-messages").find("tbody")
.append(($("<tr/>")
.append($("<td/>", { text: ((data[i].username === null) ? '' : data[i].username) }))
.append($("<td/>", { text: data[i].category }))
.append($("<td/>", { text: data[i].message }))
.append($("<td/>", {
text: data[i].created_at,
class: 'created-at',
'data-created_at': data[i].created_at
}))
));
}
}, 'json');
So, every time that I want to change the structure of the table I have to change the .php and .js files.
Now, the questions is, Is there any way to store the structure of the table in one file and every times that I want to change the structure, I just change that file?
Create all html in php page and call this php page using $.ajax request and finally use response coming from the ajax request with appropriate method $("#contact-messages").html(reponse) / $("#contact-messages").append(response) / $("#contact-messages").prepend(response).
You can use only ajax as #jQuery Angry Bird said and you should note that it would be better if you do call .append() or .html() just once and not in a loop (to reduce the execution time a little bit)
$.get("contact-messages.php", { "category": category }, function (data) {
$("#contact-messages").find("tbody").empty(); // Empty the old messages.
var tmpStr = '';
for (var i = 0; i < data.length; i++) {
tmpStr = '';
tmpStr+='<tr>';
tmpStr+='<td>'+(data[i].username === null) ? '' : data[i].username)+'<td/>';
tmpStr+='<td>'+data[i].category+'</td>'
tmpStr+='<td>'+data[i].message+'<td>'
tmpStr+='<td class="+created-at+" data-created_at="++">'+data[i].created_at+'</td>'
tmpStr+='</tr>';
}
//call .html() once instead of .append() data.length*5 times
$("#contact-messages").find("tbody").html(tmpStr);
}, 'json');
Related
Why is the url I created getting 404 instead of loading the page data set to each group I want to show on scroll?
I implemented a infinite scroll effect to paginate my data from a table in my mysql database. Now that I am trying to load the page I am getting a 404 error for the url my query is creating.
example.com/inventory-search.php?limit=15&offset=0&_=1455489762864 404 (Not Found)
I am operating under the impression that the url being formed was specifying the amount of pages and my logic should be keeping track on which page set to be shown. Loading more on scroll.
I did use a tutorial online to get this part of the logic done so I am wondering if I am assuming something that is wrong.
My code looks like this,
DB Config
$db_host = "localhost";
$db_user = "username";
$db_pass = "password";
$db_name = "dbName";
try
{
$DB_con = new PDO("mysql:host={$db_host};dbname={$db_name}",$db_user,$db_pass);
$DB_con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $exception)
{
echo $exception->getMessage();
}
?>
Inventory search script,
<?php
require_once get_stylesheet_directory() . '/wuno-search/Dbconfig.php';
$limit = (intval($_GET['limit']) != 0 ) ? $_GET['limit'] : 15;
$offset = (intval($_GET['offset']) != 0 ) ? $_GET['offset'] : 0;
$sql = "SELECT * FROM wuno_inventory WHERE 1 ORDER BY id ASC LIMIT $limit OFFSET $offset";
try {
$stmt = $DB_con->prepare($sql);
$stmt->execute();
$results = $stmt->fetchAll();
} catch (Exception $ex) {
echo $ex->getMessage();
}
if (count($results) > 0) {
foreach ($results as $res) {
echo '<tr class="invent">';
echo '<td>' . $res['wuno_product'] . '</td>';
echo '<td>' . $res['wuno_alternates'] . '</td>';
echo '<td>' . $res['wuno_description'] . '</td>';
echo '<td>' . $res['wuno_onhand'] . '</td>';
echo '<td>' . $res['wuno_condition'] . '</td>';
echo '</tr>';
}
}
?>
My Jquery
<script type="text/javascript">
jQuery(document).ready(function($) {
var busy = false;
var limit = 15;
var offset = 0;
var assetPath = "<?php echo $assetPath; ?>"
function displayRecords(lim, off) {
jQuery.ajax({
type: "GET",
async: false,
url: assetPath,
data: "limit=" + lim + "&offset=" + off,
cache: false,
beforeSend: function() {
$("#loader_message").html("").hide();
$('#loader_image').show();
},
success: function(html) {
$("#productResults").append(html);
$('#loader_image').hide();
if (html == "") {
$("#loader_message").html('<button data-atr="nodata" class="btn btn-default" type="button">No more records.</button>').show()
} else {
$("#loader_message").html('<button class="btn btn-default" type="button">Loading please wait...</button>').show();
}
window.busy = false;
}
});
}
(function($) {
$(document).ready(function() {
if (busy == false) {
busy = true;
// start to load the first set of data
displayRecords(limit, offset);
}
});
})( jQuery );
(function($) {
$(document).ready(function() {
$(window).scroll(function() {
// make sure u give the container id of the data to be loaded in.
if ($(window).scrollTop() + $(window).height() > $("#productResults").height() && !busy) {
busy = true;
offset = limit + offset;
displayRecords(limit, offset);
}
});
});
})( jQuery );
});
</script>
define $assetPath
$assetPath = get_stylesheet_directory() . '/wuno-search/inventory-search.php';
?>
There are a number of things that could be factors, but what may be the biggest issue is that you are trying to access result properties that you have not SELECTed. For example, you are trying to get $res['wuno_product'] when you have only selected id in your query. You can always do a print_r($results) or var_dump($results), etc. to see what the query is returning.
I am using jQuery (1.9.1) with jQuery Mobile (1.3.0). I am having trouble with the Reflow table in JQM. When I AJAX to get my JSON data from a script to add more rows to my table, the reflow table headings are not generated after I trigger a refresh and create on the table. Here is my code:
HTML/PHP
'<table data-role="table" id="itemTable" data-mode="reflow" class="ui-responsive table-stroke" style="display:table;">' .
'<thead>' .
'<tr>' .
'<th data-priority="1">Location</th>' .
'<th>Name</th>' .
'<th data-priority="3">Barcode</th>' .
'<th data-priority="4">Needed</th>' .
'<th data-priority="5">Scanned</th>' .
'</tr>' .
'</thead>' .
'<tbody>' .
$tableData .
'</tbody>' .
'</table>' .
JavaScript
$('.getOrder, .getStoreOrder').on('vclick', function(e) {
e.preventDefault();
var sel = this;
var theLink = $(this).attr('href');
if (activeOrder === true) {
return false;
}
$.ajax({
url: 'ajax.php',
data: {
pa: ($(sel).hasClass('getStoreOrder') ? 'store' : '') + 'order'
},
dataType: 'json',
beforeSend: function() {
$.mobile.showPageLoadingMsg();
$('#itemTable tbody').html('');
$('#leftPanel ul li').not(':first-child').remove();
},
success: function(data) {
testVar = data;
var i;
for (i=0; i <= data.length -1; i++) {
$('#itemTable tbody').append( '' +
'<tr id="item' + (i+1) + '">' +
'<td><span>' + data[i].Location + '</span></td>' +
'<td><a onclick="showImageOverlay(\'' + data[i].Image + '\');">' + data[i].Name + '</a></td>' +
'<td>' + data[i].Barcode + '</td>' +
'<td>' + data[i].Qty + '</td>' +
'<td>0</td>' +
'</tr>' +
'');
$('#leftPanel ul').append( '' +
'<li>' +
'<a href="#item' + (i+1) + '" class="itemLink" onclick="changeItem(\'item' + (i+1) + '\')">' +
'Item ' + (i+1) +
'</a>' +
'</li>' +
'');
}
$('#itemTable').trigger('refresh');
$('#itemTable').trigger('create');
$('#leftPanel #leftUl').listview('refresh');
},
complete: function() {
$('#rightPanel', '.ui-page-active').panel('close');
$.mobile.hidePageLoadingMsg();
//pageChange(theLink);
}
});
});
The AJAX does succeed and add my rows to the table how I want them to. My question is how do I trigger JQM to add the reflow column names.
I know that I can use <b class="ui-table-cell-label">Column Name</b> to my row appends to add the column names but I want it done dynamically so I don't have to change the jQuery when I change my HTML.
Thank you.
In my opinion its preferable to do like this: $('#tableContainer').load('revisedTable.php?json=yourJsonString');
That way you're doing the table layout in php rather than javascript.
Figured it out. Turns out that jQuery Mobile version 1.3.0 does not have a proper .table('refresh') method implemented. I solved this by upgrading to jQuery Mobile version 1.3.1 which has the proper method I needed.
I have a page that returns 16 records from my table.
As the user scrolls to the bottom, I then pull another 12 records from my table and append them to my previous results, my problem is that my results are being duplicated, and not in the correct order.
JS
// Ajax Getentries.php
var url = location.pathname;
if(url.indexOf('missing-people.php') > -1) {
didScroll = false;
$(window).scroll(function () {
didScroll = true;
});
setInterval(function () {
if(didScroll) {
didScroll = false;
if(($(document).height() - $(window).height()) - $(window).scrollTop() < 100) {
var number = $(".directory").children().length;
$.ajax({
type: "POST",
url: "getentries.php",
data: "count=" + number,
success: function (results) {
$('.directory').append(results).fadein();
}
});
}
}
}, 250);
}
PHP
$result = mysql_query("SELECT * FROM directory LIMIT {$_POST['count']},12");
$c = 1;
while($row = mysql_fetch_array($result))
{
echo '<div class="entry';
if (($c % 4) == 1) echo ' alpha ';
echo ' span3"><span class="name">' . $row['First_Name'] . ' ' . $row['Surname'] . "</span>";
echo '<img src="/access/upload/' . $row["picture_1"] . '" alt="' . $row['First_Name'] . ' ' . $row['Surname'] . ', missing since ' . $row['Date_Last_Seen'] . ' " />';
echo '<span class="missing-from">Last seen in ' . ucwords($row["Location_County_Last_Seen"]) . '</span>View Profile</div>';
$c++;
}
mysql_close($con);
it seems like it's a race condition. Indeed, if you quickly scroll the page this is what happens:
the setInterval gets triggered
there are already 12 images in the dom, hence var number = $(".directory").children().length is 12.
now new data is fetched from the server with ajax.
Now, if I'm still at the bottom of the page and the ajax calls hasn't completed yet, the setInterval is going to be triggered again, number still resolve to 12 and I'm going to do the same ajax request. Hence duplication.
Solving the issue could be as simple as setting number at the beginning of the script and incrementing it every time you make an ajax call.
// Ajax Getentries.php
var url = location.pathname;
var number = $(".directory").children().length;
if(url.indexOf('missing-people.php') > -1) {
didScroll = false;
$(window).scroll(function () {
didScroll = true;
});
setInterval(function () {
if(didScroll) {
didScroll = false;
if(($(document).height() - $(window).height()) - $(window).scrollTop() < 100) {
number += 12;
$.ajax({
type: "POST",
url: "getentries.php",
data: "count=" + number,
success: function (results) {
$('.directory').append(results).fadein();
}
});
}
}
}, 250);
}
I have code that dynamically creates a product features list and puts all the values together into one string seperated by newline characters and gets saved to the database. When this string is passed to the view I output as an unordered list. When I go to edit the block it does not show what is already in the list, so I have to retype all the features everytime I need to edit my block, even if it's not the feature list (I have some titles and other textareas). If I put the php variable into my edit page it will show me what has been saved but I would need it to be instantly added to the list and not showing separate. I basically need it to "auto appendTo" my <ul>. Here is my code...
controller function to save the list in controller.php
public function save($args) {
$args['features'] = implode("\n", $args['features']);//combine all feature items into one string, separated by "newline" characters
parent::save($args);
}
my edit.php - this will show it in a list. If I just put echo $features it outputs the string.
echo '<div class="ccm-block-field-group">';
echo '<h2>' . t('Features') . '</h2>';
echo '<input type="text" id="inputList" />';
echo '<button type="button" id="addList">Add</button>';
echo $features = explode("\n", $features);
foreach ($features as $feature) {
echo '<li class="currentFeatures">' . $feature . '</li>';
};
echo '<ul class="featureList">';
echo '</ul>';
echo '</div>';
my auto.js - handles creation of the list
var listItemCounter = 0;
$("#addList").click(function() {
listItemCounter++;
var text = $("#inputList").val(); //assign a unique id number to this button, so it knows which hidden field to remove when clicked
var buttonDataId = text + '<button data-id="' + listItemCounter + '">x</button>';
if(text.length){
$('<li />', {html: buttonDataId}).appendTo('ul.featureList');
$('<input type="hidden" name="features[]" value="' + text + '" data-id="' + listItemCounter + '" />').insertAfter('ul.featureList');
};
});
$('ul').on('click','button', function(el){
$('input[data-id="' + $(this).attr('data-id') + '"]').remove();//remove the hidden field so it does not get POSTed when user saves
$(this).parent().remove()
});
and finally part of my db.xml
<field name="features" type="X2"></field>
You'll want to do something similar to what I explained for the "view" in your other question ( https://stackoverflow.com/a/14968046/477513 ).
You want to change the list from a string to an array (via explode("\n", $features)), then run your javascript on each of those features. Since this is basically the same javascript that you'd do when someone adds a new item via the textbox, you will want to move all that code into a function and call the function in both situations (otherwise you will be copying and pasting the same code, which violates the "Don't Repeat Yourself" rule and inevitably leads to bugs in the future). So your auto.js code could look something like this:
var listItemCounter = 0;
function addItem(text) {
if (text.length) {
listItemCounter++;
var itemHtml = '<li data-id="' + listItemCounter + '">'
+ text
+ '<button data-id="' + listItemCounter + '">x</button>'
+ '</li>';
var inputHtml = '<input type="hidden" name="features[]" value="' + text + '" data-id="' + listItemCounter + '" />';
$('ul.featureList').append(itemHtml);
$('ul.featureList').after(inputHtml);
}
}
function removeItem(id) {
$('input[data-id="' + id + '"]').remove();
$('li[data-id="' + id + '"]').remove();
}
$("#addList").click(function() {
additem($("#inputList").val());
});
$('ul').on('click','button', function(el) {
var id = $(this).attr('data-id');
removeItem(id);
});
Then in your edit.php file, add this code to output the saved data and call the addItem function on each one:
<?php
//populate existing data when edit dialog is first opened
$featuresPHPArray = explode("\n", $features);
$featuresJSArray = Loader::helper('json')->encode($featuresPHPArray);
?>
<script>
var savedItems = <?php echo $featuresJSArray; ?>;
$.each(savedItems, function() {
addItem(this);
});
</script>
I'm following through an example which deals with the following json object passed from a php page:-
{"book":[{"title":"Harry Potter","author":"J K. Rowling","year":"2005","price":"29.99"},{"title":"Learning XML","author":"Erik T. Ray","year":"2003","price":"39.95"}]}
I know that you can iterate through and print all the data to a table as follows:
$.each(data.book, function(index, book) {
content = '<tr><td>' + book.title + '</td>';
content += '<td>' + book.author + '</td>';
content += '<td>' + book.year + '</td>';
content += '<td>' + book.price + '</td></tr>';
$(content).appendTo("#content2");
});
But say the json data is dynamic following the same structure, how can I adapt the above code to work for this? I was thinking I would need some sort of nested loop.
Whats causing me confusion is that for the line $.each(data.book, function(index, book) {
data.book will not always be data.book they would be data.foo
and the lines which refer to book.title will not always be the same it could be book.bar
Any guidance most appreciated
Yes you can do it in a nested loop like this
var content = '';
$.each(data.book, function(index, book) {
content += '<tr>';
$.each(book,function(k,v){
content += '<td>' + v + '</td>';
});
content += '</tr>';
});
$(content).appendTo("#content2");
http://jsfiddle.net/tjjQh/
Oh.. then use the for in loop
for (v in data) {
$.each(data[v], function(index, book) {
content += '<tr>';
$.each(book, function(k, v) {
content += '<td>' + v + '</td>';
});
content += '</tr>';
});
}
http://jsfiddle.net/8YCgA/
You may want to check out jQuery Templating.
var data = [
{ name : "John", age : 25 },
{ name : "Jane", age : 49 },
{ name : "Jim", age : 31 },
{ name : "Julie", age : 39 },
{ name : "Joe", age : 19 },
{ name : "Jack", age : 48 }
Can be expressed as:
<li>
<span>{%= $i + 1 %}</span>
<p><strong>Name: </strong> {%= name %}</p>
{% if ($context.options.showAge) { %}
<p><strong>Age: </strong> {%= age %}</p>
{% } %}
</li>