The following code runs on a page that gives you the ability to add and delete rows from a table of input fields. It works for existing fields, but when I add new rows and try to delete them in an order that requires replacing the ID and name attributes it doesnt work - it will not replace the ID and name attributes. Any ideas what's going on?
The following function is supposed to decrement the remaining rows after the current row that is going to be deleted has been passed in the loop, and replace the number in the ID and name attributes. Then delete the row.
$("#tblData").delegate("button", "click", function()
{
var id1 = $(this).closest('tr').find('td input').attr('id');
id1 = parseInt(id1.match(/\d+/));
var count = 0;
var ID;
var name;
var str;
var str2;
var n1, n2;
$('#tblData > tbody > tr').each(function() {
$(this).find('td').each(function(){
//do your stuff, you can use $(this) to get current cell
if ($(this).children().children().next().prop("tagName") == "INPUT")
{
if (count > id1){
// get id and name attributes
ID = $(this).children().children().next().attr("id");
name = $(this).children().children().next().attr("name");
// match number and replace number in ID
str=ID;
n1=parseInt(str.match(/\d+/));
n1 = n1-1;
ID = ID.replace(/\d+/,n1);
// match number and replace number in name
str2=name;
n2=parseInt(str2.match(/\d+/));
n2 = n2-1;
name = name.replace(/\d+/,n2);
$(this).children().children().next().attr("id",ID);
$(this).children().children().next().attr("name",name);
}
} else if ($(this).children().children().next().prop("tagName") == "SELECT") {
if (count > id1){
ID = $(this).children().children().next().attr("id");
name = $(this).children().children().next().attr("name");
// match number and replace number in ID
str=ID;
n1=parseInt(str.match(/\d+/));
n1 = n1-1;
ID = ID.replace(/\d+/,n1);
// match number and replace number in name
str2=name;
n2=parseInt(str2.match(/\d+/));
n2 = n2-1;
name = name.replace(/\d+/,n2);
$(this).children().children().next().attr("id",ID);
$(this).children().children().next().attr("name",name);
}
}
});
count = count + 1;
});
$(this).closest('tr').remove();
}
);
Append row function
function Add(){
var id = $( "#tblData tbody tr:last-child td input" ).attr('id');
id = parseInt(id.substring(12, 13)) + 1;
//alert(id);
$("#tblData tbody").append(
"<tr>"+
"<td><label for='BookingRoom_Room_No'>Room No</label><select single='single' size='1' name='BookingRoom["+id+"][roomId]' id='BookingRoom_"+id+"_roomId'><option value='1'>1</option><option value='2'>2</option></select></td>"+
"<td><label for='BookingRoom_startDate' class='required'>Start Date <span class='required'>*</span></label><input name='BookingRoom["+id+"][startDate]' id='BookingRoom_"+id+"_startDate' type='text' /></td>"+
"<td><label for='BookingRoom_endDate' class='required'>End Date <span class='required'>*</span></label><input name='BookingRoom["+id+"][endDate]' id='BookingRoom_"+id+"_endDate' type='text' /></td>"+
"<td><label for='BookingRoom_adults' class='required'>Adults <span class='required'>*</span></label><select single='single' size='5' name='BookingRoom["+id+"][adults]' id='BookingRoom_"+id+"_adults'><option value='1'>1</option><option value='2'>2</option><option value='3'>3</option><option value='4'>4</option><option value='5'>5</option></select></td>"+
"<td><label for='BookingRoom_children' class='required'>Children <span class='required'>*</span></label><select single='single' size='5' name='BookingRoom["+id+"][children]' id='BookingRoom_"+id+"_children'><option value='1'>1</option><option value='2'>2</option><option value='3'>3</option><option value='4'>4</option><option value='5'>5</option></select></td>"+
"<td><button type='button'>Delete</button></td>"+
"</tr>");
};
Don't use delegate, use on instead :
$("#tblData").on("click", "button", function()
By the way, you'll prefer use double quote character instead of single quote character to wrap HTML attributes.
And you're encapsulating too many time this with jquery in your function... a good practice is to never call twice the same element with jquery, store it in a variable instead :
var $that = $(this); // put a $ before your var to remember that it is a jquery element
Related
In a formstack form, I need to be able to pass a list to the form as a parameter and, from that list, create checkboxes or dropdown menus that the user can select and that are saved in formstack's database and sent to integrations like all other fields. Here's an example of what I'd like to send in:
http://theformurl?list=option1,option2,option3,option4
From this, I'm trying to use code insertion in either (or a mixture of) the head, footer, or a code embed to create a new field on load that looks and acts like all the other fields.
I've been tinkering with Jenna Molby's approach to dynamically modifying html with url parameters found here:
https://jennamolby.com/tutorial-examples/dynamic-content-based-on-a-url-parameter-example/
But no luck so far. At present, I've not succeeded in getting dynamic text to populate in the form, let alone a form field that then talks to formstack's back end.
Is this doable, and if so, can anyone recommend an approach or a thread to pull on to figure it out?
--update
Thanks to Eric's suggestion, I was able to get halfway there. This code in the footer can commandeer a checkbox that you've already inserted in the form by id. It will replace that checkbox with the values you send in the url. But the selections don't get caught by Formstack when you submit.
<script>
document.addEventListener("DOMContentLoaded", function(event) {
var url = new URL(window.location.href);
//Put field number in var fieldNumber
var fieldNumber = "12345678";
//Put the parameter you're searching for in var param
var param = "parameter name";
//if you want a prefix before your values in the checkbox, use prefix
var prefix = "Prefix ";
//Put the question you want to ask here.
var theQuestion = "Which of the values that came through the url will you select?";
//What should the single checkbox say if no parameters are passed?
var theDefaultBox = "No variables were contained in the parameter.";
var theField = "field" + fieldNumber;
var theFieldID = "fsCell"+fieldNumber;
var values = url.searchParams.get(param).split(",");
var theFieldHTMLfront = "";
if (values) {theFieldHTMLfront = "<fieldset id=\"label"+fieldNumber+"\"><legend class=\"fsLabel fsLabelVertical\"><span>"+theQuestion+"</span></legend><div class=\"fieldset-content\"><label class=\"fsOptionLabel vertical\" for=\""+theField+"_1\"><input type=\"checkbox\" id=\""+theField+"_1\" name=\""+theField+"[]\" value=\""+ prefix + values[0] + "\" class=\"fsField vertical\" />"+ prefix + values[0] + "</label>";} else {theFieldHTMLfront = "<fieldset id=\"label"+fieldNumber+"\"><legend class=\"fsLabel fsLabelVertical\"><span>Which values may have observed or have knowledge about this event?</span></legend><div class=\"fieldset-content\"><label class=\"fsOptionLabel vertical\" for=\""+theField+"_1\"><input type=\"checkbox\" id=\""+theField+"_1\" name=\""+theField+"[]\" value=\""+theDefaultBox+"\" class=\"fsField vertical\" />test</label>";}
var theFieldHTMLback = "</div></fieldset>";
for (var i = 1; i < values.length; i++) {
theFieldHTMLfront += "<label class=\"fsOptionLabel vertical\" for=\""+theField+(i+1)+"\"><input type=\"checkbox\" id=\""+theField+(i+1)+"\" name=\""+theField+"[]\" value=\""+prefix+values[i]+"\" class=\"fsField vertical\" />"+ prefix + values[i] + "</label>";
}
var theFieldHTML = theFieldHTMLfront + theFieldHTMLback;
document.getElementById(theFieldID).innerHTML = theFieldHTML;
});
</script>
Any thoughts on how to get it to talk to Formstack on submit?
Not familiar with formstack or what exactly you're getting from the URL and placing into forms or of what type, but I'll take a shot in the dark here.
Perhaps something like this:
var paramsToGet = ['param', 'param', 'param'];
document.addEventListener("DOMContentLoaded", function(event) {
let url = new URL(window.location.href);
paramsToGet.forEach((v)=>{
let thisParam = url.searchParams.get(param);
newFormElement(thisParam, x, x, "Default Value");
})
});
var newFormElement = (type, element_id, target_id, default_value) => {
default_value = default_value || null;
let el = document.createElement(type);
el.id = element_id;
if (default_value) {el.value = default_value;}
document.getElementById(target_id).appendChild(el);
}
So I've managed to find a solution that works for me. Thanks Eric for getting me started.
It requires adding two fields to the form you want to use this in: (1) a hidden text entry field where the selected values will be written, and (2) a placeholder checkbox field that this code will overwrite. You'll need to grab their id numbers, which I did by opening the live form and viewing source.
<script>
var selectedValues = [];
//This code goes in your Formstack theme footer. In the form that you want to add dynamic checkboxes to, create two fields using the WYSIWYG editor: a checkbox field and a text entry field. Make the text entry field hidden. You will need to know the id number of both the text entry and checkbox fields.
//Put the text entry field number in var textFieldNumber
var textFieldNumber = "field"+"12345678";
var index;
var checkboxFieldNumber = "12345679";
//Put the parameter you're searching for in var param
var param = "param";
//if you want a prefix before your values in the checkbox, use prefix
var prefix = "";
//Put the question you want to ask here.
var theQuestion = "Your question?";
//What should the single checkbox say if no parameters are passed?
var theDefaultBox = "Default message.";
document.addEventListener("DOMContentLoaded", function(event) {
var url = new URL(window.location.href);
//Put checkbox field number in var checkboxFieldNumber
//Build the replacement HTML for the placeholder checkbox field.
var theField = "field" + checkboxFieldNumber;
var theFieldID = "fsCell"+checkboxFieldNumber;
var values = url.searchParams.get(param).split(",") || null;
var theFieldHTMLfront = "";
if (values) {theFieldHTMLfront = "<fieldset id=\"label"+checkboxFieldNumber+"\"><legend class=\"fsLabel fsLabelVertical\"><span>"+theQuestion+"</span></legend><div class=\"fieldset-content\"><label class=\"fsOptionLabel vertical\" for=\""+theField+"_1\"><input type=\"checkbox\" id=\""+theField+"_1\" name=\""+theField+"[]\" value=\""+values[0]+"\" onchange=\"checkBoxToggle(this)\" class=\"fsField vertical\" />"+ prefix + values[0] + "</label>";} else {theFieldHTMLfront = "<fieldset id=\"label"+checkboxFieldNumber+"\"><legend class=\"fsLabel fsLabelVertical\"><span>Which values may have observed or have knowledge about this event?</span></legend><div class=\"fieldset-content\"><label class=\"fsOptionLabel vertical\" for=\""+theField+"_1\"><input type=\"checkbox\" id=\""+theField+"_1\" name=\""+theField+"[]\" value=\""+theDefaultBox+"\" onchange=\"checkBoxToggle(this)\" class=\"fsField vertical\" />test</label>";}
var theFieldHTMLback = "</div></fieldset>";
//iterate through the array found in the url parameters, adding a new checkbox option for each element in the array.
if (values) {for (var i = 1; i < values.length; i++) {
theFieldHTMLfront += "<label class=\"fsOptionLabel vertical\" for=\""+theField+(i+1)+"\"><input type=\"checkbox\" id=\""+theField+"_"+(i+1)+"\" name=\""+theField+"[]\" value=\""+values[i]+"\" onchange=\"checkBoxToggle(this)\" class=\"fsField vertical\" />"+ prefix + values[i] + "</label>";
};}
//finalize replacement HTML
var theFieldHTML = theFieldHTMLfront + theFieldHTMLback;
//write new HTML to DOM
document.getElementById(theFieldID).innerHTML = theFieldHTML;
});
function checkBoxToggle(thisBox) {
if(thisBox.checked) {
//When a new checkbox is selected, add its value to array selectedValues, sort it, and write it to the text entry field.
selectedValues.push(thisBox.value);
selectedValues.sort();
document.getElementById(textFieldNumber).value = selectedValues;
} else {
//When a checkbox is deselected, splice its value out of array selectedValues and write the array to the text entry field's value
index = selectedValues.indexOf(thisBox.value);
if (index > -1) {
selectedValues.splice(index, 1);
document.getElementById(textFieldNumber).value = selectedValues;
}
}
}
</script>
I have such code in my view:
<div class="box">
<input type="text" name="product[size_ids][<%= size.id %>][quantity][1]" readonly class="product_quantity" placeholder="quantity from" value="1">
</div>
In my js I'd like to change [1] into [2] or [3] and so on after [quantity], depending on how many additional forms I create. How can I do that?
This is what I have in my JS:
var i = 1
$('.add_another_price_btn').click( function (e) {
e.preventDefault();
$(this).prev().clone().insertBefore($(this));
$(this).prev().find('.remove_another_price_btn').show();
$(this).prev().find('.product_quantity').removeAttr('readonly');
$(this).prev().find('.product_quantity').attr('value', '');
//This is what I tried, but it doesn't work properly.
$(this).prev().find('.product_quantity')
.attr('name', function() { return $(this).attr('name') + '['+ (i++) + ']' });
$('.remove_another_price_btn').click( function (ee) {
ee.preventDefault();
$(this).parent().parent().remove();
});
You can do a simple string operation with substr and lastIndexOf to replace the last part of the name.
// get input and name of input
var input = $("input");
var name = input.attr("name");
// change just the last part
name = name.substr(0, name.lastIndexOf("[")) + "[2]";
// set name back to input
input.attr("name", name);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" name="product[size_ids][<%= size.id %>][quantity][1]" readonly class="product_quantity" placeholder="quantity from" value="1">
Save the clone
Break the name using substring or split and parseInt
Like this
var $clone = $(this).prev().clone(),
$prodQ = $clone.find('.product_quantity'),
name = $prodQ.attr("name"),
parts = name.split("quantity]["),
newName = parts[0]+"quantity][",
num = parseInt(parts[1],10); // or a counter
num++;
newName += num+"]";
$prodQ.removeAttr('readonly').attr('value', '').attr('name',newName);
$clone.insertBefore($(this));
$clone.find('.remove_another_price_btn').show();
I have the following code
<tr val='question'>
<td>
<input style='width: 500px' type='text' placeholder='Q.Enter your question here for radio button? '>
</tr>
How can i find the value of input box embedded in cell .
function saveUserDefQues(){
var table=document.getElementById("QuestionList");
var surveyquestionform=document.forms[0];
var count=$('#QuestionList tr').length
for (var i = 0; i<count; i++) {
var row = table.rows[i];
if(row.getAttribute('val')==='question')
{
var Cells = row.getElementsByTagName("td");;
}
}
}
document.querySelector('tr[val] > td > input').value;
Array.from(document.querySelectorAll('tr[val] > td > input')).forEach(function(entry, index, entries)
{
entry.value; // you may store the value OR process with it AS you see fit
});
Since you are using Jquery this can be done this way.
replace this line of code
var Cells = row.getElementsByTagName("td");
with
var Cells = $(row).find('td');
var inputValue = Cell.find('input').val(); // gives you value of input
Code Refactoring recommended
I would like to refactor your code as below
HTML
<tr data-val='question'> // use data-* attribute to add custom attributes into tags
<td>
<input style='width: 500px' type='text' placeholder='Q.Enter your question here for radio button? '>
</td> // close your td
</tr>
Script
function saveUserDefQues(){
var surveyquestionform = document.forms[0]; // not sure what this is for, so ill leave it as is.
$('#QuestionList tr[data-val="question"]').each(function(){ //loop all tr's which has the data-val set to question
var inputValue = $(this).find('td input').val(); //get the value of input
console.log(inputValue);
});
}
$("tr[val='question'] > td > input").val()
But first you need to write a valid HTML. </td> closing tag is missing. Also you need to put this tr in a <table>.
See this Plunker
function getResult(){
$( "tr" ).each(function( index ) {
console.log($(this).find('input').attr('placeholder') );
});
}
I'm adding text fields with a onclick. What I'm trying to do is limit the amount of boxes to about 5.
I also need to increment the number to use as an ID.
my code:
jQuery('#add_slider_image').click(function() {
var i = 0
var plus = ++i;
jQuery('.form-table').append("<tr><td><input type'text' value='' name='slider[]' /><input type='button' name='sliderbut' value='Upload' id='button' rel='"+ plus +"' /></td><tr>");
var count = jQuery.('#button').attr('rel');
if(count=5){
alert('Limit reached');
}
})
THanks
You have to put the counter variable outside the event handler, otherwise you will be starting over from zero each time.
You should put the code that adds the elements inside the if statement, so that you either show a messare or add the elements.
There is no point in reading the value from the button that you just added, when you already have the value. Besides, an id should be unique, so you would not get the value from the last button but the first.
The comparison operator is ==, if you use = you will instead assign a value to the variable, so the condition would always end up being true.
$(document).ready(function(){
var sliderCount = 0;
jQuery('#add_slider_image').click(function() {
if (sliderCount == 5) {
alert('Limit reached');
} else {
sliderCount++;
jQuery('.form-table').append('<tr><td><input type="text" value="" name="slider[]" /><input type="button" name="sliderbut" value="Upload" rel="'+ sliderCount +'" /></td><tr>');
}
});
});
I guess something like this should work:
jQuery('#add_slider_image').click(function() {
var count = jQuery("input[name='sliderbut']").length;
if (count < 5){
jQuery('.form-table').append("<tr><td><input type='text' value='' name='slider[]' /><input type='button' name='sliderbut' value='Upload' /></td><tr>");
}
})
A bit simplified fiddle there: http://jsfiddle.net/Daess/fukxu/
When you try to compare the "count" with the number 5 you have to use == instead.
count = 5 will set count to 5 and always return true if you use count == 5 it will compare your variable with the number 5 and return true or false, depending on the value of the variable.
Also I think you can easily count the number of buttons by using length, sth like: $('.button').length should return the number of elements with the class (not ID) "button".
var i = 0
var plus = ++i;
This part means that plus will always be zero and i == 1, so your rel attribute always reads 0.
var count = jQuery.('#button').attr('rel');
You are using an ID selector. And ID can exist only once per page. As you use an ID selector, you get only the first matched element which will obviously not be the one you want as you want the number in the last element.
if(count=5){
..but it doesn't matter anyway because now you're just telling that count equals 5 and the alert will always execute. What you are looking for is the comparison operator ==.
Easiest way to do this is to ditch the counts and whatnots, and just check if there are already too many elements before inserting:
jQuery('#add_slider_image').click(function() {
if($('.form-table .myRow').length < 5) {
jQuery('.form-table').append('<tr class="myRow"><td><input type="text" name="slider[]" /><input type="button" name="sliderbut" value="Upload" class="button" /></td><tr>');
}
});
Note that I added the myRow class to help identify which rows are appended and changed the id="button" to class="button".
Try this.
jQuery('#add_slider_image').click(function() {
var myHTML = "";
var current_count = jQuery('.form-table tr').length();
if (current_count >= 5) return;
for (var i = current_count; i <= 5; i++) {
myHTML += "<tr><td><input type'text' value='' name='slider[]' /><input type='button' name='sliderbut' value='Upload' id='button" + plus + "' rel='" + plus + "' /></td><tr>";
}
//touch DOM once
jQuery('.form-table').append(myHTML);
});
i am using this code to access all the hidden elements from a form:
function get_hidden_val(ids,form_id)
{
var get_check_val = document.getElementById(ids);
if(get_check_val.checked){
var div = $('<div></div>')
.appendTo('form#bulk_add_cart')
.attr('id',"bulk_"+form_id)
$("form#" +form_id).find('input[type="hidden"]').each(function(){
var value =$(this).val();
var name = $(this).attr("name");
var tags = "<input type='hidden' value='" + value + "' name='"+name+"'>";
$('div#' +form_id).append(tags);
});
}
else
{
$("form#bulk_add_cart").find('div#' +form_id).remove();
}
}
My problem is when I click the first checkbox it give me the result but when i click the second checkbox it doesn't and also the another problem is when i click first checkbox it shows total hidden elements but when i second time checked it, it show 4 less ?
Please suggest a solution.
Thanks
#user704302: Missing >, update var tags to --
var tags = "<input type='hidden' value='" + value + "' id='"+id+"'>";