Expandable Form Fields with JS - php

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.

Related

Change drop down list depending on input content

I want to emulate this booking form.
If pickup is not an airport in the drop down list, it swaps to a google maps autocomplete drop down list.
I have a database and can show the two drop down lists independently. What I want to achieve is that as you type - depending on the input content - hide one list and show the other one. (That is how I think it's done according to the website code).
If anyone could shed some light I would be very grateful.
I asked web admin but doesn't know because it has been done for him 😥
This could be the functions you could use
You may want to save the lengths and check if the length changes.
var dd1 = document.getElementById("dd1").value;
var dd2 = document.getElementById("dd2").value;
if(dd1.value.length >0 ){dd2.style.display = 'none'}
if(dd2.value.length >0 ){dd1.style.display = 'none'}
Or add an onkeypress event
dd1.onkeypress="checkkeystroke(1)"
dd1.addEventListener("keypress", function(){checkkeystroke(1);};
<input id="dd1" type="text onkeypress="checkkeystroke(1)" />;
<script>
var dropdown = [null,null,null];
const toggle = {1:[2],2:[1]};
dropdown[1] = document.getElementById("dd1");
dropdown[2] = document.getElementById("dd2");
function checkkeypress(id){
dropdown[id] = dropdown[toggle[id]].style.display = 'none';
}
</style>
That's just some basic possibilities. You would probably need to add some integrity checks. You do not want to hide both entry inputs
UPDATE
I want to show different drop downs depending on the text being
entered - and not in its length. If text written is not in the initial
drop down list, show a second drop down list
So instead of getting the length you have the "value" of the text which I needed to to get the length. You may want to get the length and segment your list of words by length. Maybe not.
Make and array of the wordlist
const wordlist = ['','','','','','',''];
if you have a different wordlist for each dropdown
then use an object instead of an array
const wordlist = {0:['','','','','','',''],1:['','','','','','',''],2:['','','','','','',''];
You need to use consecutivly numbered ids in your dropdowns
e.g.
<select id="dd0"><select id="dd1"><select id="dd2">
The following will search your wordlist and if it finds a word in teh text value it makes dropdown #3 disappear and dropdown #4 aapear.
<script>
wordlist['','','','','','',''];
var dd= [null,null,null];
for (var id in dd){
dd[id] = document.getElementById('dd' + id);
}
function keystroke(id){
for (for var key in wordlist){
if (dd[id].value.includes(wordlist[key])){
dd[3].style.display = 'none';
dd[4].style.display = 'block';
}
}
}
</script>
This should get you going if you understand my code. There are some things I'd like to explain but a client just called and I need to go back to work. I do not know your programming level. My code may be a little on the advanced side. It will be very fast and can handle a large word list so you may want to include common misspellings in your word list. If you have questions I'll be around later. There may be errors in my syntax I did not proof read the code. No time.

How to let PHP add another line for every form

I'm using Javascript to create more form fields, to be more specific I'm using jQuery append() to create copies of form fields I already have when a button is pressed.
For example there is an exercise form field, then when someone presses the + button they get another form field to add a second exercise. Now I have to get all these exercises into a PHP file, with no limit so someone could add a 1000 exercises and they would all get sent to my PHP.
I have it setup so jQuery gives them all a name tag with exercisex, the 2nd x being the number of the form field, so the original is exercise1, the second one exercise2, etc.
Now I submit the form and it gets send to another file, submitted.php.
In this file I have it setup for the original form field like this:
$exercise1 = $_POST['exercise1'];
and to put it in an array
$arrExercise = array (
>"exercise1" => $exercise1 );
What I'm looking is for a way that PHP automatically adds this:
$exercise2 = $_POST['exercise2'];
$exercise3 = $_POST['exercise3'];
and adds to the array
"exercise2" => $exercise2
"exercise3" => $exercise3
etc. for all the numbers ofcourse
Now obviously I can't add a unlimited amount into this myself so I was wondering how to get PHP to add them automatically according to how many were added.
I see the obvious risk that someone could spam it by adding a million exercises but that's not a concern for the environment this will be used in.
I tried a for loop but got stuck eventually:
I don't remember the exact code but I tried to add a variable, lets call it n, this variable would get a +1 everytime I pressed the + button so if n=1 at the start, pressing the button once makes it 2, then 3, then 4 etc. and then I got stuck thinking I'd still need to add an infinite amount of
$exercise + n = $_POST['exercise' + n];
if that would even work anyways.
Thanks for any help in advance.
I just solved a similar issue yesterday - here's how.....
The 'key' is to get the form names setup before sending to PHP.
(as you didn't give examples of your form, I will use mine for example - easy enough to port over to your project)
In my project, the user is allowed to add custom menu (nav bar) items as well as links under it, etc.
The way I solved it was to name things where PHP would get a nicely formed array in the $_POST;
<input type="text" name="menu1[Name]" value="">
<input required type="text" name="menu1[data][1][text]" value="">
<input required type="text" name="menu1[data][1][link]" value="">
'rinse/repeat' for all the form values that get added (replacing the '1' in the name with your variable) - you would also replace all 'menu1' with your 'exerciseX'
Now, put a 'Submit' button on the page;
<button type="button" id="custommenusave">Save Changes</button>
A bit of jQuery makes simple work of it....
$("#custommenusave").click(function () {
update_custom_menus();
});
function update_custom_menus() {
var form = $("#form_custom_menus");
$.post("../data/ajax.php", 'function=set_custom_menu&' + form.serialize(), function (data) {
form.submit();
});
}
PHP gets a nice array to work with (I've done a json_encode to make it simpler to see....)
{"menu1":{"Name":"'my menu #1'","data":{"1":{"text":"first","link":"https:\/\/example.com","options":"tab"},"2":{"text":"the second link","link":"http:\/\/example2.com","options":"tab"}}},"menu2":{"Name":"'menu #2!!!!'","data":{"1":{"text":"link in menu #2","link":"https:\/\/example.com","options":"tab"}}}
Then, pull your user's answers and work with them (of course, you should clean any data that comes from a user - no matter how much you 'trust' them!)
This should give you an idea of at least one way (with working code) that you can go.
name of your input should be an array so you can add multiple inputs by same name
<input required type="text" name="exercise[]">
$count = 1;
$finalArray = array();
if(is_array($_POST) && count($_POST) > 0){
foreach ($_POST as $value) {
$finalArray['exercise'.$count] = $value;
$count++;
}
}
print_r($finalArray);

Create a new table from existing table

A bit of a random exercise but I want to take content from an existing table and create a new table based on the entries taken.
In the image above, the table on the left is what I have to work with already. The blue table on the right is what I want to create; using the data from the table on the left.
Can this be done with jQuery or some basic PHP?
If you're wondering why I'm doing this its because I don't have access to the SQL database and I want to use Google Charts API to display total number of user registrations for each month.
As always, your help is MUCH appreciated.
Using JQuery it can be done in this way
//initialize monthArray
var monthArr = [{month:'April', occ:0}, {month:'May', occ:0},{month:'June', occ:0}];
//read occurrences for MonthNames in your existing table
$.each(monthArr, function(n,i){
var _occ = $("td:contains('"+monthArr[n].month+"')").size();
monthArr[n].occ = _occ;
});
// create new table and show the values
$.each(monthArr, function(index, value) {
//alert(value.occ+ ': ' + value.month);
$('#inTable').append('<tr><td>'+value.month+'</td><td>'+value.occ+'</td></tr>');
});
Here is fiddle: http://jsfiddle.net/A3WeJ/38/
Note: Table look and feel formatting has not been done in this solution
The question of whether or not you wish to use jQuery or PHP depends on whether the content of these tables is likely to change after the page has loaded. If the page will not change, you should use PHP.
Assuming the table is produced using a while or foreach loop, you can simply set up counts for each option that you have in the table. Within the loop, if you check what is in this column and add to an appropriate arbitrary count, you can count how many are in each.
It would probably be good to check what the contents is, and if it's already in your array.
Hope that provides some initial help to the thinking behind this question!
You may try this (You didn't provide more information, so just may be an idea)
HTML The id maintable could be changed with another id/class or just table
​<table id="maintable">
<thead><th>Name</th><th>Join Month</th><th>Join Year</th></thead>
<tbody>
<tr><td>Joe Blogs</td><td>April</td><td>2012</td></tr>
<tr><td>Mr. X</td><td>April</td><td>2012</td></tr>
<tr><td>Andrew Xmen</td><td>April</td><td>2012</td></tr>
<tr><td>Matt Bblogs</td><td>may</td><td>2012</td></tr>
<tr><td>Malcom McGuiness</td><td>June</td><td>2012</td></tr>
<tr><td>Friday Needavodka</td><td>June</td><td>2012</td></tr>
</tbody>
</table>
<div id="myTblDiv"></div>
JS
​$(function(){
var rows={};
$('table#maintable tbody tr').each(function(){
var item=$('td:eq(1)', $(this));
if(rows.hasOwnProperty(item.text()))
rows[item.text()]=parseInt(rows[item.text()])+1;
else rows[item.text()]=1;
});
var myTable=$('<table />', {'id':'myNewtable', 'class':'table table-striped'});
var th=$('<thead><th>Total</th><th>Month</th></thead>');
var tbody=$('<tbody></tbody>');
myTable.append(th).append(tbody);
$.each(rows, function(k, v){
var row=$('<tr><td>'+v+'</td><td>'+k+'</td></tr>');
myTable.find('tbody').append(row);
});
$('div#myTblDiv').append(myTable);
});​
DEMO or Different Style.
Notice, I've used an id (maintable) for the table generated by google, in this case you have to change the id or class (if it has any) or even you can just use table without any id or class name but make sure there is only one table when you are using only $('table'), also if you can wrap the table within a parent div then you can use $('div#parentDivId table').

Jeditable, PHP + MySQL

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).

What is the best way to go about creating a page of stickies with savable and retrievable content?

I have had a look at sticky notes with php and jquery and jStickyNote, and while both seem to look pretty nifty they lack some elements I am after. I haven't been able to find a way to allow particular users to modify the stickies they create, nor have I found a good way to save their stickies into my database. I am, and would like to keep using php, mysql and jquery. I have thought with the first link that I could just save the image created into a folder and save the url into that database but then I cannot go back and allow the user to change the content of the sticky. With the second link there does not seem to be support for saving the sticky at all. I'd also like to create a function where adding stickies to a message board (for everyone to see) does so in a randomly placed way that looks natural. Any ideas for either of these problems?
Here is some javascript that should help:
// Called when the edit (A) button is pressed
function edit(event, editButton)
{
// Get existing title and change element to textarea
var stickyTitle = $(editButton).parent().find('p.stickyTitle');
var textareaTitle = $(document.createElement('textarea')).addClass('textareaTitle');
$(textareaTitle).text(stickyTitle.html());
// Get existing description and change element to textarea
var stickyDescription = $(editButton).parent().find('p.stickyDescription');
var textareaDescription = $(document.createElement('textarea')).addClass('textareaDescription');
$(textareaDescription).text(stickyDescription.html());
// Create save button
var saveButton = $(document.createElement('div')).addClass('jSticky-create');
// Add save button, then replace title, then replace description, then remove edit button
$(editButton).before(saveButton);
$(editButton).parent().find('p.stickyTitle').before(textareaTitle).remove();
$(editButton).parent().find('p.stickyDescription').before(textareaDescription).remove();
$(editButton).remove();
// Set description textarea focus and set button actions
textareaTitle.focus();
setActions();
}
// Called when the save (tick) button is pressed
function save(event, saveButton)
{
// Get existing title and change element to paragraph
var textareaTitle = $(saveButton).parent().find('textarea.textareaTitle');
var stickyTitle = $(document.createElement('p')).addClass('stickyTitle');
var newTitleValue = textareaTitle.val();
$(stickyTitle).html(newTitleValue);
// Get existing description and change element to paragraph
var textareaDescription = $(saveButton).parent().find('textarea.textareaDescription');
var stickyDescription = $(document.createElement('p')).addClass('stickyDescription');
var newDescriptionValue = textareaDescription.val();
$(stickyDescription).html(newDescriptionValue);
// Create edit button
var editButton = $(document.createElement('div')).addClass('jSticky-edit');
// Add edit button, then replace title, then replace description, then remove save button
$(saveButton).before(editButton);
$(saveButton).parent().find('textarea.textareaTitle').before(stickyTitle).remove();
$(saveButton).parent().find('textarea.textareaDescription').before(stickyDescription).remove();
$(saveButton).remove();
// Set button actions
setActions();
// Add the object to the ads div
$('#ads').append(object);
// Update your database here
// by calling the saveAd.php
}
function setActions()
{
// call these after changes are made to anything
$('.jSticky-create').unbind('click').click(function(e)
{
save(e, this);
});
$('.jSticky-edit').unbind('click').click(function(e)
{
edit(e, this);
});
$('.jSticky-delete').unbind('click').click(function(e)
{
remove(e, this);
});
}
function remove(event, deleteButton)
{
var stickyMaster = $(deleteButton).parent();
$(stickyMaster).remove();
//then call savead.php with delete parameter
}
Have you looked at any of the code? I took a really quick look at jStickyNote.
Basically, the "sticky note" is a css-styled, text area (that is surround by a div element).
If you want users to be able to save sticky notes/edit past notes, here's what I'd recommend:
Add some button to each note that says "Save" or with a similar meaning.
When a user clicks the "Save" button, you'll need to grab the text from that specific textarea element and then save that text to a database.
With that said, you'll probably need to design some sort of database with a user table and sticknote table. The sticknote table can have a foreign key to the user table.
You'll also want to add some sort of login functionality to your site and then load the correct sticky notes for the authenticated user.
Good Luck!
You can have a look at http://sticky.appspot.com - the code has been released by the google appengine team.
Sorry for not going into specifics, but you could modify the plugin code to load a php script whenever a save button is clicked (or the box is moved, or even on keyup) with $.ajax(), passing it the horizontal and vertical positions and content of the note ( say, $("#note-content").text() ) and have the script plug those things into a database with a MySQL query. Just serialize your data and send it away. This gets more complicated if you want let your users have multiple notes, but start with one. Where is you hangup, exactly? I would be more specific, but I'm not sure what you already know.
I was thinking earlier about adding this feature to an app I'm working on. The thing is, I don't like those plugins. It should be very simple to write your own though. Let me know if you need help with something specifically.

Categories