Jeditable, PHP + MySQL - php

Okay, I'm horrendously new to MySQL and PHP, but could use some help here.
Grand vision: a big page full of editable fields (I'm using Jeditable, an edit-in-place jquery plugin) that stores values to different fields in the same row of a MySQL database.
I'm totally lost on how to properly post the values to different fields of the MySQL database, though. What I have is below; it's derived from the examples Jeditable provides. I can enter data into the fields, but it saves the ID of the field - not the data - and it appends it into multiple columns of my database, not the one correct column.
So, in short - how would I map what you see here to different locations in my MySQL database (example: one line item/record with a customer name value, a size value, an MRR at initial sale value, etc?)
Here is my HTML-
<!-- JQuery to extract form data... -->
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
$('#paragraph_1').editable('save.php');
});
$(document).ready(function() {
$('#custsize').editable('save.php');
});
$(document).ready(function() {
$('#mrratsale').editable('save.php');
});
</script>
<!-- my form fields... -->
<h2 id="paragraph_1" name="paragraph_1"></h2>
<h3 id="custsize" name="custsize"></h3>
<h3 id="mrratsale" name="mrratsale"></h3>
...and here is my save.php file...
<?php
require_once 'config.php';
$query=sprintf("INSERT INTO customerdata (ListItemID, CustName, CustSize, MrrAtSale)
VALUES (%d, '%s', '%s', '%s')",
$id, $_POST['id'], $_POST['id'], $_POST['id'], stripslashes($_POST['value']));
$dbh->exec($query);
/* What is echoed back will be shown in webpage after editing.*/
print $_POST['value'];
?>
Any help at all would be much, much, much appreciated (and try not to laugh!)

What you have to do is target each editable database write to its own function - so you can target individual fields.
So your html files should read (I also cleaned up your JS):
<!-- JQuery to extract form data... -->
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
$('.paragraph_1').editable('save.php?type=paragraph');
$('.custsize').editable('save.php?type=custsize');
$('.mrratsale').editable('save.php?type=mrratsale');
});
</script>
<!-- my form fields... -->
<h2 id="1" class="paragraph_1"></h2>
<h3 id="1" class="custsize"></h3>
<h3 id="1" class="mrratsale"></h3>
Notice how I added query strings to the save.php file. You should also change the elements' id to a field in the record, so you can update the correct record.
The php file:
<?php
require_once 'config.php';
$type = (isset($_GET['type'])) ? $_GET['type'] : "";
$value = (isset($_POST['value'])) ? $_POST['value'] : ""; //value posted
$id = (isset($_POST['id'])) ? $_POST['id'] : ""; //id of the element
if($type == "paragraph") {
mysql_query("UPDATE customerdata SET paragraph='$value' WHERE id='$id'");
} elseif ($type == "custsize") {
mysql_query("UPDATE customerdata SET CustSize='$value' WHERE id='$id'");
} elseif ($type == "mrratsale") {
mysql_query("UPDATE customerdata SET MrRatSale='$value' WHERE id='$id'");
};
print $value;
?>
You should add some validation and clean the data before putting it in the database but this should get the jEditable working.
Note that you should probably update the record rather than inserting it otherwise you will be creating a new record everytime the data is editted.
You can see the id is used to update the correct record.
I haven't really used jEditable recently but this should get you started.

Okay, I'm a bit confused. Is your problem that you are trying to target certain fields, but yet you can't? If so, make sure there is a field designated as a Primary Key and use that to specify which row you want the field to be updated. If you don't target a specific row containing a precise value to be be matched up against, I fail to see how you're going to ever change the correct record when you have more than one in a table.
Second, how are you handling all of these fields? I hope they are not just generated on the fly each time the form code is saved. I say this because unless you have a very good naming convention setup, it will be a nightmare to ever sort out data saved in that table later on. In other words, spend some time clearly labeling your fields (user_name, user_email, etc. NOT field01, field02, etc.) Also be aware that if the code is somehow creating a new field based on what fields are present/submitted, that opens up a bunch of other stuff to be mindful of. Can a person make a page with a thousand form fields in HTML, submit that and your database try and make afield for all of them? If you have some sort of field verification system in place (with some finite limits in place), I'd suggest stop relying on code you didn't make/understand to build/manage your database info automagically. Just make the fields you need and name them intelligently.
Third, why not just code the PHP and MySQL stuff by hand? Not only will that help you learn how to code better in both of those, it also sounds like the Jeditable thing is a waste of time if it doesn't work like you want with minimal tweaks. What you're describing is not hard to do - and don't use JQuery if you can help it (it's a crutch for new JS people).
Hope some of this helps/answers your question(s).

Related

issue with PHP POST values as orientation changes on an iPad

I have a website, written in PHP, which is setup to run on desktop, mobile and iPad. Everything seems fine with desktop and mobiles. However, on the iPad I have an issue where I can save submitted POST values to the database in portrait mode, but when I try doing the same thing in landscape, I just don't get the values that were actually submitted in the form from the POST.
I have the same code for the input form in both orientations. However, when I check the data received as POST values in portrait mode, I do get the data that was actually entered into the fields in the form. My problem is that when I do the same thing in landscape mode, I don’t get the submitted value from the form. Instead, I get the data for that field from the database, when there really doesn’t seem to be any way that that data could end up as the POST value. This really doesn’t seem possible considering how my code is set up.
I will now talk you through key parts of my code in all of this.
I have two JavaScript functions in the header section of my index.php file, which are used to check orientation and also to respond to orientation changes (as shown below). These hide/show divs for each orientation in the body of the same index.php file. These do both work, as I see the page content change correctly on the iPad, as I change its orientation.
function check_orientation() // check orientation for ipad home page.
{
var div_portrait = document.getElementById('ipad_home_page_portrait');
var div_landscape = document.getElementById('ipad_home_page_landscape');
if(window.innerHeight > window.innerWidth)
{
div_landscape.style.display = 'none';
div_portrait.style.display = 'block';
}
else
{
div_portrait.style.display = 'none';
div_landscape.style.display = 'block';
}
}
window.addEventListener("orientationchange", function()
{
var div_portrait = document.getElementById('ipad_home_page_portrait');
var div_landscape = document.getElementById('ipad_home_page_landscape');
if (window.orientation == 0)
{
div_landscape.style.display = 'none';
div_portrait.style.display = 'block';
}
else
{
div_portrait.style.display = 'none';
div_landscape.style.display = 'block';
}
}
, false);
In the body of index.php, I have the following which has been simplified, to keep this from getting any longer than it already is. At the same time all the key/relevant bits of code have been included:
<body onload='check_orientation();'>
<div id='ipad_home_page_landscape'>
<?php include ('view_edit_company_ipad.php'); ?>
</div>
<div id='ipad_home_page_portrait'>
<?php include ('view_edit_company_ipad.php'); ?>
</div>
</body>
As stated above I use the same code file in both orientations (as can be seen in the 2 divs above). I get this to work by using conditional code at key points in the file for setting the widths and heights of page components.
The file ‘view_edit_company_ipad.php’ includes a form which allows the user to input data, etc. The following is one the fields from that form:
<input type='text' name='company_contact_name' value='<?php
if (isset($company_contact_name)) echo $company_contact_name; ?>' />
As I’ve already stated, I can get the data inserted into the form in portrait mode, if I check the POST value with the following code:
<?php echo $_POST[‘company_contact_name’]; ?>
However, if I do the same thing in landscape mode, I don’t get the value that was submitted in the form, even when all the code is exactly the same.
Also, I use that echo statement right at the very top of my index.php file, so there is no way that any of my code has changed that POST value. I just don’t get the data that was inserted as 'company_contact_name' from that echo statement when I’m using the iPad in landscape mode.
I realise that I've written a lot here, but I couldn't give all the required info, if I'd made it any shorter. Big thanks to anyone who reads this and even bigger thanks, if you can offer a solution of any sort.
Try var_dump() dumping the entire $_POST superglobal to see what the script receives from the browser.
I suspect the isssue is with multiple form control names within the same form. If both the divs code is within the same form and in both divs you have the input with name company_contact_name then only one of them (the one in the portrait div) is sent on form submission.
If this is the case, then check out the solution at Multiple inputs with same name through POST in php
Basically you can have an array of inputs, though you could also rename one of them.

Keeping some selected options after submitting form

Thanks in advance for any suggestions on the following:
I've created a php-page to add works from composers to CDs in a database. It's a combination of two forms and looks like this:
1st form:
Composer : [drop down list] : Select
Some blank space
2nd form:
Title : [drop down list]
Track number : [empty varchar field]
Work : [drop down list]
some other fields
Process button
After selecting a name in the first block (posting to $_SERVER["PHP_SELF"]) I stay on the same page, that name is shown in the blank space in between and the drop down lists are populated with only CD titles and works of the selected composer.
I can then select from the lists and enter other data in the other fields. Hitting the process button posts the data from the second block to another page which will eventually send everything to a table in a MySQL database.
After that I send myself back to the first page with header("Location: the_first_page.php")
So far so good, but upon returning I would like the composer, title and work to be preselected. Now I'm sent to a blank page and have to start from scratch. I think I've seen some solution involving testing $_POST['something'] against <option value> in a drop down list but I can't seem to make that work.
My question is: Is there a way to send $_POST['Title'] and $_POST['Work'] back to the first page somehow? Or is it better to split the two forms over seperate pages?
All help is welcome.
You could use sessions or the post data itself. For using the post data itself, the page where you send the request should be the same and include the script that will process it if there's some data like this:
if (!empty($_POST)) {
include "save.php";
}
// More code...
?>
<select name = "a">
<option <?php if ($_POST['a'] == "test") echo "selected"; ?> value = "test">
<option <?php if ($_POST['a'] == "testb") echo "selected"; ?> value = "testb">
</select>
Of course there are many more ways, but this is just a simple one to get you started. Things to know: you might want to change the variable $_POST and clean it up before using it. In this case it should be fine, but in <input type = "text" value = "<?= $_POST['b']; ?> name = "b">` you have a serious security issue.
For sanitizing the input, you want to sanitize it respect to what you expect. But also, as an EXTRA meassure, you normally want to strip everything that looks like a <script>, onclick ="", ' DROP TABLE users and similar. It's not an easy subject, so I recommend you reading on it, mainly on the XSS attacks which is relevant to showing the text back to the user. While it might seem too much work for this "simple case", it is useful in many more situations.
Use session variables and put conditions for them ... see [ $_SESSION ].

Expandable Form Fields with JS

I may just be searching Google using the wrong keywords but I am having very little luck finding information on creating expandable form fields. I have an input form where a user can list all of the inventory assigned to a server node, but would like for them to be able to add additional items if needed. Example being the form shows an option for (1) Disk to be added but they can click a + symbol and add more.
I already created 8 MYSQL rows for each type such as disk1, disk2, etc. to allow for a considerable amount to be stored. However, my concern is that this works out to be a LOT of options.
1) How can I use Javascript to create expandable forms? I only found one code example that didn't work.
2) Should I hard-code all of the options? Such as, right now my code has a Select box named "ram", "motherboard", etc. Could I generate these or should I go ahead and write it out for each field such as "ram1", "ram2", etc?
Cloning the field in JavaScript is easy. Say you have:
<select name="hdd"><!-- ...options here...--></select>
then once you get a reference to that existing element in the DOM (see below), you can do this:
var newSelect = existingSelect.cloneNode(true);
newSelect.selectedIndex = -1; // To clear any existing selection
existingSelect.parentNode.insertBefore(newSelect, existingSelect.nextSibling);
Getting the reference to the existing select can be done on any modern browser using a CSS selector and document.querySelector (to get the first match) or document.querySelectorAll (to get a list of all matches), for instance:
var list = document.querySelectorAll('select[name="hdd"]');
var existingSelect = list[list.length - 1]; // Get the last one
...which will give you the last one. Or more likely, you have a row of some kind (a tr, or a div) containing that which you want to copy. Not a problem, give that row a class (say, "hdd"), and clone the entire thing (here I'm cloning the last row and adding it to the end):
var list = document.querySelectorAll('.hdd');
var existingRow = list[list.length - 1]; // Get the last one
var newRow = existingRow.cloneNode(true); // Clone it
newRow.querySelector('select[name="hdd"]').selectedIndex = -1; // Clear selected value
existingRow.parentNode.insertBefore(newRow, existingRow.nextSibling);
On the MySQL side of things, it's best not to have columns like hdd1, hdd2, etc., because it makes queries on those fields complicated and does, of course, limit the maximum number you can have (granted you'll probably want to limit that anyway). (Having those columns in one row is called "denormalizing" the DB.)
The usual way to do that in DB design is to have a second table, listing HDDs, where a key in that second table (a "foreign key") links back to your main table. (See "database normalization" for more information.)
So your main table might have a record id, say SystemID. Your HDDs table would then have a SystemID column and an HDD column, where it could have many rows for the same SystemID.
Here's a complete example of the form bit: Live Copy | Live Source
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Add Form Field Example</title>
</head>
<body>
<div class="hdd">
<label>HDD: <select name="hdd">
<option>--choose--</option>
<option>80GB</option>
<option>500GB</option>
<option>1TB</option>
<option>2TB</option>
</select></label></div>
<input type="button" id="theButton" value="Add Row">
<script>
(function() {
document.getElementById("theButton").addEventListener("click", addRow, false);
function addRow() {
var list = document.querySelectorAll('.hdd');
var existingRow = list[list.length - 1]; // Get the last one
var newRow = existingRow.cloneNode(true); // Clone it
newRow.querySelector('select[name="hdd"]').selectedIndex = -1; // Clear selected value
existingRow.parentNode.insertBefore(newRow, existingRow.nextSibling);
}
})();
</script>
</body>
</html>
Some useful references:
Selectors Level 1
DOM3 Core
DOM2 HTML
HTML5 Specification
Try creating a generic DEVICE_DETAIL table, with columns for TYPE and DETAILS. Then you can hold an arbitrary number & add new types in the future.
create table DEVICE (
ID integer not null,
..
primary key (ID)
);
create table DEVICE_DETAIL (
ID integer not null,
FK_DEVICE integer not null,
"TYPE" varchar(24), -- type code; defined internally.
CONFIG varchar(200),
NOTES clob, -- if necessary?
.. more columns if useful
primary key (ID)
);
The benefit of this, is that you don't need separate tables for HDD, IP addresses, RAM, or a wide range of future possibilities. You just need a couple of columns which can hold the details -- and for most things, one line will suffice.
Add & show new fields in the UI, as the user fills out the previous ones.
The simplest way to do this is to register an "Add Field" click handler, and use that to create a new field in Javascript. I've put together a quick example to show you how to do this with input fields.
Here's the HTML:
<form id='form'>
<div>
<label for='input0'>Field 0</label>
<input name='input0' type='text'></input>
</div>
</form>
<a id='moreLink' href='#'>Add Field</a>
Here's the Javascript:
var inputIndex = 0;
document.getElementById('moreLink').addEventListener('click', function() {
var form = document.getElementById('form'),
newLabel = document.createElement('label'),
newInput = document.createElement('input'),
newDiv = document.createElement('div'),
inputId
;
inputIndex++;
inputId = 'input' + inputIndex;
newLabel.htmlFor = inputId;
newLabel.innerHTML = 'Field ' + inputIndex;
newInput.name = inputId;
newInput.type = 'text';
newDiv.appendChild(newLabel);
newDiv.appendChild(newInput);
form.appendChild(newDiv);
});
And here's a link to a JSFiddle so you can see it in action: http://jsfiddle.net/tpmet/
This is a pretty naive solution, but it'll perform fine and will work in any browser you throw at it, at least as far back as IE6.
If your markup gets more complicated, you should consider creating a template once at startup and cloning that template in the click handler. And if you plan to add entire forms or other large amounts of DOM, I'd recommend reading up on Document Fragments, which are more complicated but would perform better at that level of scale.
Hope this was helpful, please comment if my answer is unclear.

Validating dynamic number of form elements in PHP

I need to make a form where client information can be added by people at the administration department. On the first form page, information like client name, address and contact details can be entered, as well as whether or not the client has children.
The form gets validated by PHP. If the client does not have children, the data is saved to the database. If the client does have children, the form data gets saved in hidden form fields, and a second form page is shown, where up to 10 children and can be added.
However, on initial page view, only one text input is visible. With a javascript button, more text input fields can dynamically be added (until the limit of 10 is reached).
The problem is the validation in PHP. If one of the text inputs contains a non-valid string, the form should be re-displayed with the right number of fields, and those containing errors in a special HTML class (in the CSS i give that class a red border for usability reasons, so the user can immediately see where the error resides). However, because the adding of fields happens with Javascript, the form gets re-displayed with only one field.
Any ideas on how to address this problem are very welcome. I'm proficient in PHP, but JavaScript is very new to me, so I'm not able to make big changes to the script i found to dynamically add fields.
I've dealt with something similar in the past. There are a couple of options that come to mind.
Since you have JS code to generate new fields at the click of the button, why not expand that JS function so it can also be called with some parameters passed. If there are parameters, it will populate the fields with existing data.
Then, if the form is being re-displayed due to errors, or for editing, from PHP, pass some information to Javascript so that when the page loads, you create the fields and populate them with data.
To illustrate, I assume you have something like this:
Add Another Child
And you have the function:
function addNewFormField() {
// create new HTML element to contain the field
// create new input, append to element container
// add container to DOM
}
Change it so it is like this:
function addNewFormField(data) {
// create new HTML element to contain the field
// create new input, append to element container
// add container to DOM
if (data != undefined) {
newFormElement.value = data.value;
newContainerElement.class = 'error';
}
}
And from PHP, add some code that runs onload:
<script type="text/javascript">
window.onload = function() { // replace me with jQuery ready() or something proper
<?php foreach($childInList as $child): ?>
addNewFormField({ value: '<?php echo $child['name'] ?>' });
<?php endforeach; ?>
}
</script>
Hope that helps, its a high level example without knowing exactly how your form works but I've used similar methods in the past to re-populate JS created fields with data from the server side.
EDIT: Another method you could use would be to create the HTML elements on the PHP side and pre-populate them from there, but that could end up with duplicate code, HTML generation from JS and HTML generation of the same stuff from PHP. As long as the JS side was smart enough to recognize the initial fields added by PHP you can go with whatever is easiest to implement. Personally I'd just extend your JS code to handle optional data like illustrated above.

Saving multiple forms to a session without knowing input names

<form id="questions_1">
<div data-role="collapsible-set" data-theme="" data-content-theme="" id='q1'>
<!-- GETS QUESTIONS FROM THE DATABASE -->
</div>
</form>
So I have a form that goes on for 5 pages like shown above, and I want to save all the data from each step, I am thinking something along the lines of this to pass all the data for each form into a .php page:
function formSubmit1() {
$("#questions_1").submit(function() {
$.post('addToSession.php',$("#questions_1").serialize().function(data) {
});
return false;
});
}
By adding the following code to each "submit"/next page button I think I can call the function.
<a data-role="button" href="#questions_2" onClick=formSubmit1()>Next</a>
This might need some customization but the part I am really unsure about is how do I get all the data without knowing their id's. The idea is to make the questions in this poll vary in order, size and questions so I need a general code that can handle any input.
Use $_REQUEST to get data from forms on submit. After getting data $_SESSION['name'] = $_REQUEST.

Categories