I'm trying to manage a dynamic menu based on results from tables in my database.
Code below is so far i have come.. But i can't get it to display as i want to.
i have 3 tables in my database looking like this.
ws_categories
id
maincat (name of main-category)
ws_subcategories
id
subcat (Name of sub-category)
parentcat (id of main-category)
ws_subsubs
id
subsub (Name of 2nd-sub-category)
parentsub (id of sub-category)
What i want to achieve?
Having a simple vertical menu, that outputs main categories, and onclick, submenue alternatives related to that main category will show, if a sub category has a 3rd submenu/submenues, they will show under..
Code below is so far i have come.. But i don't seem to understand why it output main category several times and not just once..
To be clear, i do not understand how i should use join to achieve this. I want to be able to echo all main categories once, and subcategories once, and if there is one or more 2nd sub categories i want them to echo too.. How do i achieve this with join? is it even possible or am i looking the wrong way?
Thanks in advance.
PHP
<?php
echo '<div class="dl_parent">';
$results = mysqli_query($link, "SELECT * FROM `ws_categories` INNER JOIN `ws_subcategories` ON `ws_categories`.`id` = `ws_subcategories`.`parentcat`;") or die (mysqli_error($link));
while($row = mysqli_fetch_array($results)){
echo '
<div class="dl_parent">
<div class="dl_link">'.$row['maincat'].'</div>
<div class="dl_sub_dd">
<ul>
<li>'.$row['subcat'].'</li>
</ul>
</div>
</div>
';
}
?>
Javascript
$(window).on('load',function(){
//CLICK-HANDLERS=============================
$('.dl_link').click(function(){
var submenu = $(this).parent().children('.dl_sub_dd');
if (submenu.css('display') == 'none') {
$('.dl_sub_dd').hide(); //first hide any previously showing submenu's
submenu.show(); //then show the current submenu
} else {
submenu.hide(); //hide the current submenu again
}
});
});
CSS
/*LINK------------------------*/
.dl_link {
cursor:pointer;
}
/*DROPMENU--------------------*/
.dl_sub_dd {
display:none;
}
Your SQL request will give you for each main category as many rows as it has sub categories:
row 1: maincat1 | subcat1
row 2: maincat1 | subcat2
etc...
You could make a request to select all maincats, and for each maincat, make another request to select all its subcats. Something like this:
PHP
<?php
$results = mysqli_query($link, "SELECT * FROM `ws_categories`;") or die (mysqli_error($link));
while($row = mysqli_fetch_array($results)){
echo '
<div class="dl_parent">
<div class="dl_link">'.$row['maincat'].'</div>
<div class="dl_sub_dd">
<ul>';
$query = mysqli_query($link, "SELECT * FROM `ws_categories` INNER JOIN `ws_subcategories` ON `ws_categories`.`id` = `ws_subcategories`.`parentcat` WHERE `ws_categories`.`id` = " . $row['id'] . ";") or die (mysqli_error($link));
while($row2 = mysqli_fetch_array($query)) {
echo '<li>'.$row2['subcat'].'</li>';
}
echo '</ul>
</div>
</div>
';
}
?>
Related
This is the div that i am updating
but i want to add a active class to the (li) item
every time the div refreshes the active class goes away
so i don`t want to refresh all the data in the (ul) but
only add (li) if there is a new data in the database,
with out refreshing the previous (li) items
<div id="contacts">
<ul id="rooms" class="rooms">
<!-- This is where the data get inserted -->
<!-- the ajax call and this -->
<li class='contact' data-val='<?php echo $room['id']; ?>'>
<div class='wrap'>
<div class='meta'>
<p class='name'><?php echo $room['sender']; ?></p>
<p class='preview'><?php echo $room['senderemail']; ?></p>
</div>
</div>
</li>
</ul>
</div>
this is my ajax call
$(document).ready(function() {
var interval = setInterval(function(){
$.ajax({
url: 'rooms.php',
success: function(data){
$('#rooms').html(data);
}
});
}, 1000);
});
in the room php
$rooms = get_rooms();
foreach($rooms as $room){
?>
<li class='contact' data-val='<?php echo $room['id']; ?>'>
<div class='wrap'>
<div class='meta'>
<p class='name'><?php echo $room['sender']; ?></p>
<p class='preview'><?php echo $room['senderemail']; ?></p>
</div>
</div>
</li>
<?php
}
the get_rooms() function
function get_rooms() {
$sql = "SELECT id, sender, senderemail FROM chatroom ";
$result = mysqli_query($GLOBALS['dbh'], $sql);
$rooms = array();
while($room = mysqli_fetch_assoc($result)){
$rooms[] = array('id'=>$room['id'], 'sender'=>$room['sender'],
'senderemail'=>$room['senderemail']);
}
return $rooms;
}
You Just need to push new data to the div as below just replace your line with:
$('#rooms').append(data);
this will add new <li> in your existing <div> after the last <li>
jquery append()
To get the id of the last <li>
var lastId = $( "#rooms li" ).last().attr('id');
Once you get the last id then pass it in your ajax call.
If I understand you correctly, your problem is that you lose the active class (which you clicked on the li container) when there is new data.
This has to do with the fact that you exchange all of the content.
There are now three options. Either
You give the rooms.php the id of the currently active li-container
and this script sets the active class for the affected container.
You transfer all the chatrooms (ids) already shown to rooms.php and only
load the new ones (this means effort later with sorting).
You save the active li class and re set it after content changed (this is the fastest)
f.e: in your Ajax succes functions:
let id=0;
let active_li = $('li.active');
if (active_li.length>0) id=active_li.data('val');
$('#rooms').html(data);
if (id!=0) $('li[data-val="'+id+'"]').addClass ('active');
A few other thoughts:
Note the interval of 1000ms. Possible it makes Problems if the request lasts longer than 1000ms. This may still work well in your tests, but maybe not anymore if there are a hundred or 1000 users in your application.
Doesn't it make sense to tell the server when you click the active room and save it in a session so that the server knows which room is active in the client?
You need to simply update your JS code like:
$(document).ready(function() {
var active_list = '';
var interval = setInterval(function(){
$.ajax({
url: 'rooms.php',
beforeSend: function(){
active_list = $('#rooms').find('li.contact.active').attr('data-val');
}
success: function(data){
$('#rooms').html(data);
$(data).find('li[data-val="' + active_list +'"]').addClass('active');
}
});
}, 1000);
});
This should solve your problem and Let me know if you still face any issue.
I need to display a table that corresponds to the value chosen after I select a value in a dropdown list. If I run this query in my SQLPro Studio, and obviously without the $mr_id variable, it says that MR_ID is ambiguous. Is there a way to fix this? This seems like a small problem to me but I can't seem to figure it out. I just need to make sure there is a WHERE clause somewhere so that it will only display the values that correlate to the value selected.
The table is only 2 columns, MR_ID (which is what is displayed in the dropdown list and also concatenated with another column not in the table) and Supp_ID.
<?php
$host="xxxxxxxxxxxx";
$dbName="xxxxx";
$dbUser="xxxxxxxx";
$dbPass="xxxxxxxxxxxxxx";
$mr_id = $_POST['mr_id'];
$dbh = new PDO( "sqlsrv:server=".$host."; Database=".$dbName, $dbUser, $dbPass);
$dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$sql_one = "
SELECT CONCAT(CAST(Stage_Rebate_Index.MR_ID AS INT),' - ', Stage_Rebate_Master.MR_Name) AS MR_ID,
Stage_Rebate_Index.MR_ID AS sort_column,
CAST(Supp_ID as INT) AS Supp_ID
FROM Stage_Rebate_Index
LEFT JOIN Stage_Rebate_Master
ON Stage_Rebate_Master.MR_ID = Stage_Rebate_Index.MR_ID
WHERE Stage_Rebate_Index.MR_ID = '$mr_id'
ORDER BY sort_column";
//$users = $dbh->query($sql);
$users_one = $dbh->query($sql_one);
?>
<html>
<body>
<!-- Table -->
<p>
<div id="table_div">
<table border="1" id="index_table" class="ui-widget ui-widget-content">
<thead>
<tr class="ui-widget-header">
<td>MR ID</td>
<td>Supplier ID</td>
</tr>
</thead>
<?php foreach($users_one->fetchAll() as $supp) { ?>
<tr>
<td class="mr_id"><?php echo $supp['MR_ID'];?></td>
<td class="supp_id"><?php echo $supp['Supp_ID'];?></td>
</tr>
<?php } ?>
</table>
</div>
</body>
</html>
EDIT:
Updated query with harcoded value...
$sql_one = "
SELECT
CONCAT(CAST(t1.MR_ID AS INT),' - ', COALESCE(t2.MR_Name, '')) AS MR_ID,
t1.MR_ID AS sort_column,
CAST(Supp_ID as INT) AS Supp_ID
FROM Stage_Rebate_Index t1
LEFT JOIN Stage_Rebate_Master t2
ON t2.MR_ID = t1.MR_ID
WHERE
CONCAT(CAST(t1.MR_ID AS INT),' - ', t2.MR_Name) = LTRIM(RTRIM('1 - Company A'))
ORDER BY sort_column";
In your where clause
WHERE
MR_ID = '$mr_id'
Specify the table you want it from as such:
WHERE
Stage_Rebate_Master.MR_ID = '$mr_id'
You should probably also specify the tables in your select clause too.
From your comment on Zackary Murphy's solution, it sounds like your MR_ID you want in the where is actually the computed value in the select, not the column value on the tables. Try this.
SELECT
CONCAT(CAST(t1.MR_ID AS INT),' - ', COALESCE(t2.MR_Name, '')) AS MR_ID,
t1.MR_ID AS sort_column,
CAST(Supp_ID as INT) AS Supp_ID
FROM Stage_Rebate_Index t1
LEFT JOIN Stage_Rebate_Master t2
ON t2.MR_ID = t1.MR_ID
WHERE
CONCAT(CAST(t1.MR_ID AS INT),' - ', t2.MR_Name) = LTRIM(RTRIM('$mr_id'))
ORDER BY sort_column
*Edit to add table aliases.
*Edit Added white space trim.
*Edit added COALESCE in case t2.MR_Name is null.
You have to give fully qualified name of table columns.
Like you have 2 tables, table1 and table2, and have col1 as column name in both table
If you are retrieving data from these 2 table below is query example
select
table1.co11 as tbl1col1, table2.col1 as tbl2col1
from
table1
join
table2 on table1.id = table2.id
where
table1.col1 = "your statement" and table2.col1 = "your statement"
Reading a lot about sessions and how to add and remove items. I see there are a lot of different way's to get this done. I'm having the same problem.
I hope someone here could help me out with this one. I've come along way from nothing to where I am now with the help of this community (thanks!).
This is my problem, I hope I can explain it so you can understand.
Let say I have a shop that sells t-shirts and pants. When I save a t-hirt item to my cart it display's it like it should. But I'm not able to remove the item. If I then filter my page for pans (this triggers an AJAX event) and try to remove the t-shirt, the item is removed. But ALL items are removed not just the one I clicked on to remove.
Here is my HTML to add a product:
<button type="submit"
class="btn btn-primary text-right add-product showtoast"
data-target="post-<?php the_ID(); ?>"
data-attribute="<?php the_title(); ?>"
data-product="<?php the_title(); ?>">
Add to cart
</button>
And this is the HTML to remove an item:
<div class="echo-product">
<?php echo htmlspecialchars($product); ?>
<input type="submit" class="delete-product" value="Remove">
</div>
These are my Javascripts to add and remove items:
$('.add-product').click(function() {
var productName = $(this).data('product');
$.post('http://example.com/reload.php?addparam',
{productName: productName}, function(data) {
$('.txtHint').html(data);
})
});
$('.delete-product').click(function() {
var productName = $(this).data('product');
$.post('http://examples.com/reload.php?delparam',
{productName: productName}, function(data) {
$('.txtHint').html(data);
})
});
And last but not least, my reload.php script:
<?php
session_start();
if (!array_key_exists('products', $_SESSION) || !is_array($_SESSION['products'])) {
$_SESSION['products'] = [];
}
$productName = array_key_exists('productName', $_POST) ? (string) $_POST['productName'] : '';
if(isset($_GET['delparam'])){
unset($_SESSION['products'][$productName]);
}
if(isset($_GET['addparam'])){
$_SESSION['products'][] = $productName;
}
?>
<?php foreach ($_SESSION['products'] as $product): ?>
<div class="echo-product">
<i style="color:#F60;padding-right:20px;" class="fa fa-anchor" aria-hidden="true"></i>
<?php echo htmlspecialchars($product); ?>
<input type="submit" class="delete-product" value="Remove">
</div>
<?php endforeach;?>
Is there anyone that could help me understand why (it looks like) an AJAX event has to take place before I'm able to remove items. And why it removes ALL the items when I just click on one item?
Thanks!
Compare how products are added vs. how they are deleted
if(isset($_GET['delparam'])){
unset($_SESSION['products'][$productName]);
}
if(isset($_GET['addparam'])){
$_SESSION['products'][] = $productName;
}
When adding a product, you just append the productName to an array. The entry receives an numeric index.
When deleting a product you look for the productName as index - but that does not exist!
I'm sure it doesn't answer why all products are removed, but it might help to do things right.
i am using ul li to display menus, menus fetched from database
$Features = $session->get('Features');
foreach ($Features as $menuItems) {
$order_priority = $menuItems->order_priority;
$name = $menuItems->name;
$path = $menuItems->path;
}
here below the menu listed ,
<li>
<a href="<?php echo Url::to($path);?>">
<?php echo $menuItems->name; ?>
</a>
</li>
my question is i want to display the menu SORT with order_priority [1,2,3,4]?
If your order_priority attribute doesn't repeats. You can try this:
$menu = [];
foreach ($session->get('Features') as $menuItems) {
$menu[$menuItems->order_priority] = Html::a($menuItems->name, $menuItems->path);
}
ksort($menu);
And for generate the list, you can do like this:
echo Html::ul($menu)
But if it does repeat, you could sort the items in your db query like #ustmaestro said in the comments.
I have three db tables.
-Paid
-Partially Paid
-Owes
When someone registers for an account I send their user_id, name, etc to my 'Owes' db table and then output their name into a drag and drop table I have in the 'Owes' column. As of now if I move anyone's name to any other category (Paid/Partially paid) I am not sure how to delete that record from the Owes db and insert the name into the new db table so the changes are permanent.
What's really throwing me off is how to do it with the drag and drop table. I'm not sure how to apply the logic that when something is dropped into that column that the past record is deleted and a new one is added to that specific table or how to make the changes without a submit button or page reload.
What is a way I can do this and how could I structure it?
PHP
<?php
//Payment Section
$con = mysqli_connect("localhost", "root", "", "db");
$paid_run = mysqli_query($con,"SELECT * FROM paid ORDER BY id DESC");
$partially_paid_run = mysqli_query($con,"SELECT * FROM partial_payment ORDER BY id DESC");
$owes_run = mysqli_query($con,"SELECT * FROM owes ORDER BY id DESC");
$paid_numrows = mysqli_num_rows($paid_run);
$partially_paid_numrows = mysqli_num_rows($partially_paid_run);
$owes_numrows = mysqli_num_rows($owes_run);
if($paid_numrows > 0){
while($row = mysqli_fetch_assoc($paid_run)){
$paid_id = $row['user_id'];
$paid_name = $row['name'];
}
}
if($partially_paid_numrows > 0){
while($row = mysqli_fetch_assoc($partially_paid_run)){
$partially_paid_id = $row['user_id'];
$partially_paid_name = $row['name'];
$partially_paid_amount = $row['payment'];
}
}
if($owes_numrows > 0){
while($row = mysqli_fetch_assoc($owes_run)){
$owes_id = $row['user_id'];
$owes_name = $row['name'];
}
}
?>
$(function() {
$( "#paid, #partially_paid, #owes" ).sortable({
connectWith: ".tdPayment",
remove: function(e, ui) {
var $this = $(this);
var childs = $this.find('div');
if (childs.length === 0) {
$this.text("Nothing");
}
},
receive: function(e, ui) {
$(this).contents().filter(function() {
return this.nodeType == 3; //Node.TEXT_NODE
}).remove();
},
}).disableSelection();
});
Table
<table class="paymentTable" id="dragTable">
<tr>
<th class="thPayment">Paid</th>
<th class="thPayment">Partially Paid</th>
<th class="thPayment">Owes</th>
</tr>
<tr>
<td class="tdPayment" id="paid">
<div>
<?php
if ($paid_name == true) {
echo $paid_name;
} else {
echo "No one has paid";
}
?>
</div>
</td>
<td class="tdPayment" id="partially_paid">
<div>
<?php
if ($partially_paid__name == true) {
echo $partially_paid__name . " - " . $partially_paid_amount;
} else {
echo "No one has made a partial payment";
}
?>
</div>
</td>
<td class="tdPayment" id="owes">
<div>
<?php
if ($owes_name == true) {
echo $owes_name;
} else {
echo "Everyone has paid something";
}
?>
</div>
</td>
</tr>
</table>
Here's a rough outline on how to do it. I would recommend using jQuery, a JavaScript library that has a lot of useful stuff for this.
Implement the drag and drop part using jQuery draggable and droppable. A nice guide can be found here.
Write a PHP page that updates the database the way you want it.
Use jQuery to call that page when something is dropped. This can be done using Ajax.
Clarification of part 3
I recommend looking at the photo manager in the droppable documentation to get a full working example of something similar.
For this to work, you need to set up the HTML so it has some class names and some data attributes:
<h1>Owes</h1>
<div class="bin" data-bin-id="1">
<div class="user" data-user-id="5">Eva</a>
<div class="user" data-user-id="8">Anna</a>
</div>
<h1>Partially paid</h1>
<div class="bin" data-bin-id="2">
<div class="user" data-user-id="2">Tom</a>
...
</div>
...
Then we need to implement some javascript that takes care of calling the PHP when the user drops something:
jQuery(".bin").droppable({
accept: ".user",
drop: function( event, ui ) {
//Get the ID of the bin the user was dropped into.
var intBinID = jQuery(this).attr("data-bin-id");
//Get the ID of the user that was dropped.
var intUserID = ui.droppable.attr("data-user-id");
//Make an ajax call to the PHP page.
jQuery.ajax("update.php?binid=" + intBinID + "&userid=" + intUserID);
}
});
In addition you might want update.php to return something to let the JavaScript know if it worked or not, and if it failed abort the drop.
Disclaimar: Since I don't have all the parts of this project set up, I have not tested this code.
An easier way to do this, is by creating an independent User table where you keep all the users. Then, in a separate table like the ones you have already, you just keep the Id of that user (and maybe some information related to how much he owes or has already payed).
This way, when you have to insert or to update any information about the state of the user, you just have to insert/delete the Id of the User from these tables.
The information about the user will always be safe and kept in it's own table.