I have a multistep form in my project, the first step of which has a javascript extend field function where a user can add additional fields. If the user goes to the next step, the data is of course stored in Session until final submission. However, the extended form will not be remembered. If the user goes back from next step the additional field and its data is not displayed, worse still, if the data in the additional field is invalid, the user won't see it, as the message is displayed underneath the disappeared field (I'm using Cakephp default validation).
Is there a way, like storing the setting in session, to make it stay?
var counter = 0;
function moreFields(val1, val2, val3) {
counter++;
var newField = document.getElementById(val1).cloneNode(true);
newField.id = '';
newField.style.display = 'block';
var newFields = newField.querySelectorAll('[name], [id], [for], [data-display]');
for (var i=0;i<newFields.length;i++) {
var theNames = newFields[i].name
if (theNames)
newFields[i].name = "data[" + val3 + "][" + counter + "][" + theNames + "]";
var theNames2 = newFields[i].id;
if (theNames2)
newFields[i].id = theNames2 + counter;
console.log(newFields[i].id);
var theNames3 = newFields[i].htmlFor;
if (theNames3)
newFields[i].htmlFor = theNames3 + counter;
//console.log(newFields[i].htmlFor);
var theNames4 = newFields[i].dataset.display;
if (theNames4)
newFields[i].dataset.display = theNames4 + counter;
console.log(newFields[i].dataset.display);
}
var insertHere = document.getElementById(val2);
insertHere.parentNode.insertBefore(newField,insertHere);
}
<span id="readroot" style="display: none">
<div class="row">
<div class="col-lg-6">
<div class="form-group required">
<label for="Student1Grade">Grade</label>
<select name="grade" data-display="#display_student_1_grade" class="form-control" id="Student1Grade" required="required">
<option value="">Please Select</option>
<option value="1">Grade 1</option>
<option value="1">Grade 2</option>
</select>
</div>
</div>
<div class="col-lg-6">
<div class="form-group">
<label for="Student1Gender">Gender</label>
<select name="gender" data-display="#display_student_1_gender" class="form-control" id="Student1Gender">
<option value="1">Male</option>
<option value="2">Female</option>
</select>
</div>
</div>
</div>
<input class="btn btn-default" type="button" value="Remove" onclick="this.parentNode.parentNode.removeChild(this.parentNode);" /><br /><br />
</span>
<span id="writeroot"></span>
<input class="btn btn-default" type="button" onclick="moreFields('readroot', 'writeroot', 'Student')" value="Add Field" />
You need to implement either sessionStorage or localStorage for your page.
localStorage - stores data with no expiration date
sessionStorage - stores data for one session (data is lost when the browser tab is closed)
Here I am just posting sample code for your help through which u can do your desire task. You just need to follow the logical concept from below code and implement in your code.
There is a sample also which is only containing id but you can implement it in other way which can full fill your task.
click here
Related
SOLVED! Check below for solution
Hello so I need help on figuring out how this will go. This is the case:
Visualization
Firebase Data
Once the user selects a "Vehicle Number" on the list, the "VIN" and "Plate #" textboxes will automatically update with the corresponding data from the database.
In the example with the mock data, once the user selects "A_012", the VIN readonly textbox should only show "KIA9183891284" and the plate # should only show "KIA-0987".
This is currently the HTML and JS codes I used
HTML:
<div class="form-group">
<label for="vehinum">Vehicle Number</label>
<select class="form-control" name="vehicle_num" id="vehinumInput">
</select>
</div>
<div class="form-group">
<label for="vin">VIN</label>
<input type="text" name="vin" class="form-control" id="vinInput" readonly="true">
</div>
<div class="form-group">
<label for="platenum">Plate #</label>
<input type="text" name="plate_no" class="form-control" id="platenoInput" readonly="true">
</div>
JS:
var database = firebase.database();
database.ref('vehicles').once('value', function(snapshot){
if(snapshot.exists()){
var vehi_list = '';
snapshot.forEach(function(data){
var val = data.val();
vehi_list += '<option value="' + val.vehicle_number + '">' + val.vehicle_number + '</option>';
});
$('#vehinumInput').append(vehi_list);
}
I really don't know how to move forward from here. So I am looking for advice or answers on how this will go.
Thank you for taking your time to read!
So after a ton of research, I finally managed to find the answer
HTML:
<div class="form-group" id="vehi_num_mainte">
<label for="exampleFormControlInput100">Vehicle Number</label>
<select class="form-control" name="vehicle_num1" id="numberInput1" onchange="vehi_num_mainte_event();">
<option>-- Select Vehicle --</option>
</select>
</div>
<div class="form-group">
<label for="exampleFormControlInput101">VIN</label>
<input type="text" name="vin_maintenance" class="form-control" id="vinInput1" readonly="true">
</div>
<div class="form-group">
<label for="exampleFormControlInput102">Plate #</label>
<input type="text" name="plate_no1" class="form-control" id="platenoInput1" readonly="true">
</div>
JS:
function vehi_num_mainte_event()
{
//Get text or inner html of the selected option
var d = document.getElementById("numberInput1");
var selectedText = d.options[d.selectedIndex].text;
firebase.database().ref('vehicles').child('vehicle_number').on('value', function(vehinumSnapshot) {
var vehinumChildSnapshot = vehinumSnapshot.val();
var queryRef = firebase.database().ref('vehicles').orderByChild('vehicle_number').equalTo(selectedText);
queryRef.on('value', function(querySnapshot) {
querySnapshot.forEach(function(dinoSnapshot) {
var vin_mainte = '';
var plate_mainte = '';
var val = dinoSnapshot.val();
vin_mainte += val.vin;
plate_mainte += val.plate_no;
document.getElementById('vinInput1').value = vin_mainte;
document.getElementById('platenoInput1').value = plate_mainte;
});
});
});
}
These were my references:
Javascript HTML element get selected select option text value notepad ++
Firebase Docs (Retrieve Data)
I'm currently trying to create a form that will extend on click using the method shown from this site. http://www.quirksmode.org/dom/domform.html
I have the Extending of the form more or less working fine, My issue is getting the Date field to correctly step up from the date that the user inputs in the first field.
Right now if I click on Add another Date, it adds a day to 1970-01-01 which i'm assuming is a default start date somewhere.
I'm not familiar enough with javascript to reference the generated date to the date that is initially selected by the User.
Here is a fiddle link of you want to see what I mean. https://jsfiddle.net/2nvz6kqj/9/
Note i'm pretty sure you can only get the date field to show up in Chrome correctly.
And here is my code.
<script type="text/javascript">
var counter = 0;
function moreFields() {
var date = document.getElementById("myDate").value;
counter++;
var newFields = document.getElementById("readroot").cloneNode(true);
newFields.id = '';
newFields.style.display = 'block';
var newField = newFields.childNodes;
for (var i=0;i<newField.length;i++) {
var theName = newField[i].name;
if (theName)
newField[i].name = theName + counter;
}
var insertHere = document.getElementById("writeroot");
insertHere.parentNode.insertBefore(newFields,insertHere);
document.getElementById("myDate").stepUp(1);
}
window.onload = moreFields;
</script>
<body>
<div id="readroot" style="display: none">
<input type="button" value="Remove Date"
onclick="this.parentNode.parentNode.removeChild(this.parentNode);" /><br /><br />
<input type="date" id="myDate" value="">
<select name="rankingsel">
<option>School Day</option>
<option value="day1">Day 1</option>
<option value="day2">Day 2</option>
<option value="day3">Day 3</option>
<option value="day4">Day 4</option>
<option value="day5">Day 5</option>
<option value="closed">School Closed</option>
</select><br /><br />
</div>
<form method="post" action="/cgi-bin/show_params.cgi">
<span id="writeroot"></span>
<input type="button" onclick="moreFields()" value="Add Another Date" />
<input type="submit" value="Send form" />
</form>
</body>
Ultimately once i get this working correctly, I'll submit it to a DB with PHP.
Ok, I changed a few things, but this should work for you.
NOTE: In order to keep the code and markup close to what you had, I didn't "fix" some of the JavaScript and HTML that I consider to be bad practice.
I also took some liberties with the readroot element IDs and writeroot is now a DIV not a SPAN as you had it.
<html>
<head>
<script type="text/javascript">
var counter = 0;
var date = new Date();
// this function adds a day to the date variable
function addDay (dateObj) {
var ticks = dateObj.getTime();
var newTicks = ticks + (24 * 60 * 60 * 1000);
dateObj.setTime(newTicks);
}
function moreFields() {
//var dateVal = document.getElementById("myDate").value;
counter++;
// querySelector is nicer way to get your elements
var newFields = document.querySelector("#readroot").cloneNode(true);
newFields.id = newFields.id + counter;
newFields.style = null;
// nifty way to convert node list into an array
var fields = Array.prototype.slice.call(newFields.childNodes);
// now use forEach instead of old-style for loop
fields.forEach(function (f,i,nodes) {
var theName = f.name;
if (theName) {
f.id = theName + counter;
}
});
// convert "writeroot" to div and just append the newFields container
var form = document.querySelector('#writeroot');
form.appendChild(newFields);
// to set the date, you need to use an ISO-format date string
var dateFields = form.querySelectorAll('[name="myDate"]');
var len = dateFields.length;
var dateField = dateFields[len - 1];
if (dateField) {
var dateISO = date.toISOString().substr(0,10);
dateField.value = dateISO;
addDay(date);
}
}
window.onload = moreFields;
</script>
</head>
<body>
<div id="readroot" style="display: none">
<input type="button" value="Remove Date"
onclick="this.parentNode.parentNode.removeChild(this.parentNode);" /><br /><br />
<input type="date" name="myDate">
<select name="rankingsel">
<option>School Day</option>
<option value="day1">Day 1</option>
<option value="day2">Day 2</option>
<option value="day3">Day 3</option>
<option value="day4">Day 4</option>
<option value="day5">Day 5</option>
<option value="closed">School Closed</option>
</select><br /><br />
</div>
<form method="post" action="/cgi-bin/show_params.cgi">
<div id="writeroot"></div>
<input type="button" onclick="moreFields()" value="Add Another Date" />
<input type="submit" value="Send form" />
</form>
</body>
</html>
http://www.quirksmode.org/dom/domform.html
I am trying to implement this extend form function in my project. Since I am compiling with CakePHP naming convention, in my extend form I have 2 field names:
[Student][0][age]
[Student][0][grade]
The script doesn't work because it is appending the counter only at the end of a field name all alike like this: fieldName + counter, whereas I am trying to increment, as you might have guessed it, like this:
[Student][1][age]
[Student][1][grade]
[Student][2][age]
[Student][2][grade]
I am new to Javascript and hopefully someone can advise how to work this out.
HTML:
<span id="readroot" style="display: none">
<input class="btn btn-default" type="button" value="Remove review" onclick="this.parentNode.parentNode.removeChild(this.parentNode);" />
<br /><br />
<div class="row">
<div class="col-lg-3">
<div class="form-group required"><label for="Student1Age">Age</label><input name="data[Student][0][age]" class="form-control" placeholder="Age" maxlength="11" type="text" id="Student1Age" required="required"/></div>
</div>
<div class="col-lg-3">
<div class="form-group required">
<label for="Student1Grade">級別</label>
<select name="data[Student][0][grade]" class="form-control" id="Student1Grade" required="required">
<option value="">Please Select</option>
<option value="1">Grade 1</option>
<option value="2">Grade 2</option>
</select>
</div>
</div>
</div></span>
<span id="writeroot"></span><input class="btn btn-default" type="button" onclick="moreFields()" value="Give me more fields!" />
Javascript:
var counter = 0;
function moreFields() {
counter++;
var newFields = document.getElementById('readroot').cloneNode(true);
newFields.id = '';
newFields.style.display = 'block';
var newField = newFields.childNodes;
for (var i=0;i<newField.length;i++) {
var theName = newField[i].name
if (theName)
newField[i].name = theName + counter;
}
var insertHere = document.getElementById('writeroot');
insertHere.parentNode.insertBefore(newFields,insertHere);
}
You have to replace this one line like follows.
Yours:
newField[i].name = theName + counter;
New one:
newField[i].name = "[Student][" + counter + "][" + theName + "]";
I made a working sample page out of your script. Check the following link.
http://sugunan.net/demo/extend_form.php
I am trying to implement automatically HTML using form value.
When user enter the information in the form, the JS will create the correspond HTML for him.
For example.
<div class="row" id="1">
<div class="form-group col-lg-2">
<select class="form-control" name="tag">
<option value="p" selected>p</option>
<option value="br">br</option>
</select>
</div>
<div class="form-group col-lg-2">
<select class="form-control" name="class">
<option value="Day" selected>Day</option>
<option value="BlockTime">BlockTime</option>
<option value="BlockTitle">BlockTitle</option>
<option value="Session">Session</option>
<option value="Person">Person</option>
<option value="Firm">Firm</option>
</select>
</div>
<div class="form-group col-lg-7">
<textarea class="form-control" rows="3" name="content"></textarea>
</div>
<div class="form-group col-lg-1">
<input type="button" class="btn btn-default" onclick="addLine()" value="Add">
</div>
</div>
The user selected P, Day, Test message, and the press "Add" button, the button will call function addLine(). The main part is below, I didn't make it right.
var currentTag = currentLine.find("select[name='tag'] option:selected").text();
var currentClass = currentLine.find("select[name='class'] option:selected").text();
var currentText = currentLine.find("textarea").val();
var new_content = $("<currentTag></currentTag>").addClass(currentClass).html(currentText);
Now the currentTag will get the value "p", currentClass will get "Day", currentText do get "Test message", this has been done.
This is what I want, the jQuery creates HTML code like this:
<p class="Day">Test message</p>
And I want to store the HTML code to a variable called new_content. ...
If you have a container for these elements, you could just append them to it:
First you want to set your new line as a variable:
var newElements = [];
var i = 0; //Make an index counter so you can use it later if you want to. This is optional
/* Do your selection script */
var htmlElement = "<" + currentTag + " class='" + currentClass + "'>" + currentText + "</" + currentTag + ">";
newElement.push(htmlElement, i);
$('.container').append(htmlElement);
i++; //increment your i to create an index
/* Make sure all of this is inside your selection script. */
I have a rather long complicated form to be used to record field data. One section of the form requires the ability to add a "Field Blank" section with no data recorded AND the ability to add a duplicate section where everything (including the data from the field blank section) is duplicated. The only different thing that would change on the duplicate would be the SampleID
The field blank script
<script>
var counter = 0;
function moreFields() {
counter++;
var newFields = document.getElementById('readroot').cloneNode(true);
newFields.id = '';
newFields.style.display = 'block';
var newField = newFields.childNodes;
for (var i=0;i<newField.length;i++) {
var theName = newField[i].name
if (theName)
newField[i].name = theName + counter;
}
var insertHere = document.getElementById('writeroot');
insertHere.parentNode.insertBefore(newFields,insertHere);
}
</script>
The duplicate script
<script>
$(document).ready(function(){
var template_index=0;
$("#add_FieldDup").click(function(){
template_index++;
$(this).parent().before($("#template").clone().attr("id","template" + template_index));
$("#template" + template_index).css("display","inline");
$("#template" + template_index + " :input").each(function(){
$(this).attr("name",$(this).attr("name") + template_index);
$(this).attr("id",$(this).attr("id") + template_index);
});
$("#remove_Dup" + template_index).click(function(){
$(this).closest("fieldset").remove();
});
});
});
</script>
My form
<h3>Water Samples</h3>
<fieldset id="template"> <!--for the duplicate-->
<div id="template"> <!--for the duplicate-->
Sample ID: <input type="text" id="SampleID" name="SampleID"></div>
<div class="_40" data-role="controlgroup" data-mini="true" data-type="horizontal">
<label> Collection Method</label><br />
<input type="radio" id="radGrab" value="grab" name="Collection" />
<label for="radGrab">Grab</label>
<input type="radio" id="radEWI" value="EWI" name="Collection" />
<label for="radEWI">EWI</label>
</div>
<fieldset> <!--For the field blank-->
<div id="readroot" class="hidden"> <!--For the field blank-->
QA Sample ID:<input type="text" id="QASampleID" name="QASampleID">
<div class="_30" data-role="controlgroup" data-mini="true" data-type="horizontal">
<label>Collection Method</label><br />
<input type="radio" id="radGrab1" value="Grab" name="Collection1" />
<label for="radGrab1">Grab</label>
<input type="radio" id="radEWI1" value="EWI" name="Collection1" />
<label for="radEWI1">EWI</label></div>
</div>
<label class="analysis-label" for="analysis">Analyte:</label>
<select class="analysis" id="analysis" name="analysis" data-iconpos="left" data-icon="grid">
<option>Select</option>
<option value = "TN">TN</option>
<option value = "TP,NO2+3">TP,NO2+3</option>
</select>
<label class="preserve-label" for="preserve">Preserved</label>
<select class="select_preserve" id="preserve" name="preserve" data-iconpos="left" data-icon="grid">
<option>Select</option>
<option value = "HNO3">HNO₃</option>
<option value = "H2SO4">H₂SO₄</option>
</select>
<label class="cool-label" for="cool">Cooled</label>
<select class="select_cool" id="cool" name="cool" data-iconpos="left" data-icon="grid">
<option>Select</option>
<option value = "Ice">Ice</option>
<option value = "Frozen">Frozen</option>
<option value = "None">None</option>
</select>
</div> <!--Fieldblank-->
</fieldset> <!--Fieldblank -->
<hr /><span id="writeroot"></span>
</div> <!--duplicate template-->
</fieldset> <!--duplicate template-->
<button type="button" data-theme="b" data-icon="plus" id="moreFields" onclick="moreFields()">ADD FIELD BLANK</button>
<button type="button" data-theme="b" data-icon="plus" id="add_FieldDup">ADD FIELD DUP</button>
I got the duplicate to work (when the field blank wasn't hidden) but I cannot get the field blank to work. Any assistance would be greatly appreciated!
You should extract your javascript from your dom, put it in separate js and make function work in any of this blocks, create class="template" block and inside give any needed interaction buttons and inputs classes so there can exist multiple parent elements with same inside structure... then cloning does not get in a way of your interaction logic.
In js go like:
$(document).ready(function() {
$(".template .interaction_button_one").on('click', function(){
//... here you go traversing like
$(this).parents('.template').find('.some_important_div').show();
})
});
Notice .on(), this is delegation, and it will give same interaction bindings to all of your elements.