I have a form which is using the SheepIt jQuery plugin, for duplication of form rows. One of the elements in the row is a <select> element. When a certain value is chosen in the select value, a modal (I'm using Fancybox on my site) containing a <textarea> appears, allowing users to provide additional information. My idea was to take this text and add it to the form in a hidden form element, but I can't for the life of me get the text using jQuery. I've tried using .val(), .text(), and .html(), but I keep getting an empty string. I even tried using vanilla Javascript using similar methods to above, but I still can't get it to work. I have a hidden element (<input type="hidden" id="row_id" value="" />) in that same block of HTML and have no problem retrieving it using $("#row_id").val(). Any suggestions?
My Code
HTML
<!-- sheepIt Form -->
<div id="meta_fields" class="well sheepit-form">
<!-- Form template-->
<div id="meta_fields_template" class="sheepit-row">
<input id="meta_fields_#index#_field_label" name="meta[meta_fields][#index#][field_label]" type="text" placeholder="Field Label" />
<select id="meta_fields_#index#_field_type" name="meta[meta_fields][#index#][field_type]" class="field-choice">
<option value="">--Field Type--</option>
<option value="text">Single Line Text Box</option>
<option value="textarea">Multi Line Text Box</option>
<option value="checkbox">Checkbox</option>
<option value="select">Dropdown List</option>
</select>
<input id="meta_fields_#index#_field_id" name="meta[meta_fields][#index#][field_id]" type="hidden" />
<input id="meta_fields_#index#_field_required" name="meta[meta_fields][#index#][field_required]" value="0" type="hidden" />
<input id="meta_fields_#index#_field_required" name="meta[meta_fields][#index#][field_required]" value="1" type="checkbox" />
<label for="meta_fields_#index#_field_required">Required?</label>
<a id="meta_fields_remove_current" class="item small">
<i class="icon-remove"></i>
</a>
</div>
<!-- /Form template-->
<!-- No forms template -->
<div id="meta_fields_noforms_template">No fields defined!</div>
<!-- /No forms template-->
<!-- Controls -->
<div id="meta_fields_controls" class="sheepit-buttons">
<span id="meta_fields_add"><button class="btn btn-success btn-small"><i class="icon-plus-sign"></i> <span>Add Row</span></button></span>
<span id="meta_fields_remove_last"><button class="btn btn-warning btn-small"><i class="icon-remove"></i> <span>Remove Row</span></button></span>
<span id="meta_fields_remove_all"><button class="btn btn-danger btn-small"><i class="icon-trash"></i> <span>Remove All Rows</span></button></span>
</div>
<!-- /Controls -->
</div>
<!-- /sheepIt Form -->
<script type="text/x-handlebars" id="select-options-form">
<p class="lead">Please provide options for the dropdown list. One option per line</p>
<div>
<textarea id="options" style="width:500px;height:200px"></textarea>
<input type="hidden" id="row_id" value="" />
</div>
<div class="pull-right">
<button class="btn btn-success closeModal">
<i class="icon-ok"></i>
Complete
</button>
</div>
</script>
NOTE: This is not a true Handlebars template. I'm using the <script> tag to hold the HTML fragment that is inserted into the modal. I wasn't sure if having a div with style="display:none" was causing JS to think that there were two elements in the page (that was my original markup).
Javascript
// called from <select> event handler
function checkFieldList(e)
{
e.preventDefault();
var value = $(this).val();
if(value !== 'select') {
// TODO: do some processing here
return false;
}
// get the sheepIt row id -- easiest by parsing out the element ID
var row_id = parseInt($(this).prop("id").split("_")[2], 10);
return openModal(row_id);
}
function openModal(row_id)
{
// load in content and open in modal
var modalContent = $("#select-options-form");
modalContent.find("#row_id").val(row_id);
$.fancybox({
"width" : 600,
"height" : 300,
"modal" : true,
"content" : modalContent.html(),
"afterShow" : bindModalClose,
"beforeClose" : closeModal
});
}
function bindModalClose()
{
$(".closeModal").on('click', function(e) {
e.preventDefault();
$.fancybox.close();
});
}
function closeModal()
{
//add link after select dropdown and wire an event handler
var row_id = $("#row_id").val(),
dropdown = $("#meta_fields_" + row_id + "_field_type");
addOptionsLink(dropdown, row_id);
// retrieve content in <textarea>
// all the following return empty string
var text = $("#options").val();
// var text = $("#options").html();
// var text = $("#options").text();
// var text = document.getElementById("options").value;
// var text = document.getElementById("options").innerHTML;
// var text = document.getElementById("options").innerText;
console.log(text);
// 3. insert that content into hidden form field
}
function addOptionsLink(dropdown, row_id)
{
dropdown.after('View Options');
$(".load_options").on('click', function(e) {
e.preventDefault();
return openModal(row_id);
});
}
And...of course right after I resort to asking the question on StackOverflow, it's working just fine now with the $("#options").val(); solution. It's been a long week...
Related
I have an html page which has around six different forms with different somewhat unrelated fields in each form. What I'm trying to do is create a single jquery or javascript function to handle all the Fetch() on form submit without knowing the form ID (which is most of what I found in tutorials online). Right now I'm just trying to get the form data to display in an alert, but the alert is always blank (no form data being passed?).
My code for what I think should capture any form submit and display the form data:
<script>
$(document).ready(function() {
$("form").on("submit", function(e) {
console.log("CCCCCCC in script CCCCCCCCCc")
e.preventDefault();
var dataString = $(this).serialize();
alert(dataString);
return false;
});
});
</script>
I have a couple of these type of forms (took out bootstrap class info for ease of reading:
<form>
<div>
<div>
<label for="thing1">Choose:</label>
<select id="thing1" name="thing1">
<option value="XXX">XXX</option>
<option value="YYY">YYY</option>
</select>
</div>
<div>
<label for="inputtext">Command</label>
<input type="text" id="inputtext" name="thing2">
</div>
<div>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
How can I get any of the form data into the alert box? Ideally later I will use fetch() after I massage the input string.
The form doesn't have any serializable data.
A form control's data comes from a combination of its name and value but none of your form controls have name attributes.
As #Quentin suggested, you need to give a name to select and input elements, in order to get their values.
For instance:
$('form').submit(function(e) {
e.preventDefault();
var el_1 = this.thing1;
var el_2 = this.inputtext;
alert(el_1.value + ', ' + el_2.value);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<form>
<div>
<div>
<label for="thing1">Choose:</label>
<select id="thing1" name="thing1">
<option value="XXX">XXX</option>
<option value="YYY">YYY</option>
</select>
</div>
<div>
<label for="inputtext">Command</label>
<input type="text" id="inputtext" name="inputtext">
</div>
<div>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
I'm using Jquery in order to add dynamic inputs on my page. I only want to display one input initially, then more can be added by clicking a button.
This works as expected.
I'm then using PHP in order to catch the $_POST values of the inputs and send them to an external script. This also works, however I'm always receiving one extra item in my array, and it's empty.
I think this is because I have a hidden <div> field in my HTML, which is shown when a new input is generated?
My code is below;
HTML
// unnecessary code removed
<div class="after-add-more">
<button class="add-more" type="button" title="Add"></button>
<input name="addmore[]" value="" type="text">
</div>
<div class="copy-fields hide">
<div>
<button class="remove" type="button" title="Remove"></button>
<input type="text" name="addmore[]" value="">
</div>
</div>
JQUERY
$(document).ready(function() {
//here first get the contents of the div with name class copy-fields and add it to after "after-add-more" div class.
$(".add-more").click(function() {
var html = $(".copy-fields").html();
$(".after-add-more").after(html);
});
//here it will remove the current value of the remove button which has been pressed
$("body").on("click", ".remove", function() {
$(this).parents(".control-group").remove();
});
});
PHP
<?php
// unnecessary code removed
$field_values_array = $_POST['addmore'];
?>
Without generating an additional input, I enter 1111111 into the input box and submit. A print_r($_POST) produces;
[addmore] => Array
(
[0] => 1111111
[1] =>
)
Any help is appreciated.
You are probably better just getting the parent of the element that was clicked and adding your markup after that. Here is an example:
$(document).ready(function() {
// this function handles the click event
function addField(parent) {
// find your template, in this case its the first .after-add-more
var html = $(".after-add-more").first().clone();
// reset the value of any inputs
$('input', html).val('');
// wire the click handler for the button
$("button", html).click(function() {
addField($(this).parent());
});
// append it to the parent of the parent, addContainer
html.appendTo(parent.parent());
}
// wire the click handler for the add-more button
$(".add-more").click(function() {
addField($(this).parent());
});
// I don't know what the intention of this code is so I'm leaving it alone
$("body").on("click", ".remove", function() {
$(this).parents(".control-group").remove();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
// unnecessary code removed
<div id="addContainer">
<div class="after-add-more">
<button class="add-more" type="button" title="Add">Add</button>
<input name="addmore[]" value="" type="text">
</div>
</div>
<div class="copy-fields hide">
<div>
<button class="remove" type="button" title="Remove">Remove</button>
<input type="text" name="addmore[]" value="">
</div>
</div>
I have a textarea inside a div with a select dropdown underneath, and underneath that are two buttons. One is to preview, and the other is going to be for Uploading the text to a file.
I am trying to hide the Upload button if the textarea is empty. My javascript is not working since it always hides the button.
Here is the form, button container, and select dropdown (with all of the options left out since there are 20 of them):
<div class="container">
<label for="text-area">Paste your code here: </label>
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]); ?>">
<textarea name="code_input" id="code_textarea" class="form-control" rows="15" placeholder="Start coding!" required><?= isset($_POST['code_input']) ? $_POST['code_input'] : '' ?></textarea>
<div class="button-container">
<select required name="language-select" class="form-control" id="language_selector">
<option value="" selected disabled>Language</option>
<option>20 options follow</option>
<!-- THIS WILL KEEP THE VALUE IN THE DROPDOWN AFTER SUBMIT -->
<script type="text/javascript">
document.getElementById('language_selector').value = "<?php echo $_POST['language-select'];?>";
</script>
</select>
<br/>
<br/>
<div id="button-container" class="btn-toolbar">
<button id="drive_submit_btn" class="btn btn-md" type="submit">Preview</button>
<button id="upload_btn" class="btn btn-md" type="submit">Upload</button>
</div>
</div>
</form>
<div class="show-code">
<script src="lib/prism.js"></script>
<!-- THIS DISPLAYS THE CODE AFTER SUBMITTING USING THE PRISM.JS PLUGIN FOR SYNTAX HIGHLIGHTING -->
<!-- Get language selection from dropdown and append it to language class. Echo the text as highlighted code -->
<pre><code class="language-<?php echo $language ?>"><?php echo $user_code; ?></code></pre>
</div>
</div>
<!-- THIS IS THE JAVASCRIPT TO HIDE THE BUTTON UNTIL TEXT IS ENTERED.-->
<!-- HOWEVER IT ALWAYS HIDES IT!! -->
<script>
$(document).ready(function() {
/* I EVEN TRIED TO TRIM IT TO NO AVAIL */
var content = $.trim($('#code_textarea').val());
if(content.length === 0) {
$('#upload_btn').hide();
} else {
$('#upload_btn').show();
}
});
</script>
I've seen so many answers that link to their JSFiddle, and they all work fine. What is causing mine not to work correctly? Everything else works fine except for my JS function.
A native javascript solution.
Upload button is hidden from beginning, when a keyup event is fired for the textarea, the content of the textarea is checked and the button is either shown or hidden again
code_textarea.addEventListener('keyup', function(){
if(code_textarea.value){
upload_btn.classList.remove("hidden");
}
else {
upload_btn.classList.add("hidden");
}
});
.hidden {
display:none;
}
<textarea name="code_input" id="code_textarea" class="form-control" rows="5" placeholder="Start coding!" required></textarea>
<button id="upload_btn" class="btn btn-md hidden" type="submit">Upload</button>
Attach your handler to textarea's 'keyup' event.
(And start with invisible btn.)
$(document).keyup('.code_textarea',function() {
/* I EVEN TRIED TO TRIM IT TO NO AVAIL */
var content = $.trim($('#code_textarea').val());
if(content.length === 0) {
$('#upload_btn').hide();
} else {
$('#upload_btn').show();
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<label for="text-area">Paste your code here: </label>
<form method="post" >
<textarea name="code_input" id="code_textarea" class="form-control" rows="5" placeholder="Start coding!" required></textarea>
<div class="button-container">
<select required name="language-select" class="form-control" id="language_selector">
<option value="" selected disabled>Language</option>
<option>20 options follow</option>
<!-- THIS WILL KEEP THE VALUE IN THE DROPDOWN AFTER SUBMIT -->
<script type="text/javascript">
document.getElementById('language_selector').value = "";
</script>
</select>
<br/>
<br/>
<div id="button-container" class="btn-toolbar">
<button id="drive_submit_btn" class="btn btn-md" type="submit">Preview</button>
<button style="display:none" id="upload_btn" class="btn btn-md" type="submit">Upload</button>
</div>
</div>
</form>
<div class="show-code">
<script src="lib/prism.js"></script>
<!-- THIS DISPLAYS THE CODE AFTER SUBMITTING USING THE PRISM.JS PLUGIN FOR SYNTAX HIGHLIGHTING -->
<!-- Get language selection from dropdown and append it to language class. Echo the text as highlighted code -->
<pre><code class="language-"></code></pre>
</div>
</div>
<!-- THIS IS THE JAVASCRIPT TO HIDE THE BUTTON UNTIL TEXT IS ENTERED.-->
<!-- HOWEVER IT ALWAYS HIDES IT!! -->
I have a smarty template that uses jQuery clones; i.e. a click on a button will call jQuery and jQuery will add a select field to a page. However, the select field is supposed to be dynamically populated within the smarty template.
I have outlined below what i'm trying to achieve.
addProject.php
// Load supervisor list into an object and pass it to smarty
$smarty->assign_by_ref('supervisor', $supervisor->results());
$smarty->display('superusers/addProject.tpl');
superusers/addProject.tpl
<div>
<p class="add add-data add-another-supervisor2"><i class="sprite plus2"></i> <span>Add <b class="hide">another</b> supervsior</span></p>
</div>
<script src="js/cloneformcontrols.js"></script>
js/cloneformcontrols.js
$("#main").on("click", ".add-data", function() {
var mytarget = $(this).closest('.clonable').find('.clone:last');
var myparent = $(this).closest('.clonable');
var filename = "../smarty/templates/default/superusers/clones/add-supervisor.tpl";
var theCloneHtml = '<div class="clone" id="cloneID' + formNameIncrement + '">';
var theCloneId = 'cloneID' + formNameIncrement;
if ($(this).hasClass('add-another-supervisor2')) {filename = "../smarty/templates/default/superusers/clones/add-another-supervisor.tpl";}
myparent.addClass('data-added');
mytarget.after($(theCloneHtml).load(filename, function() {
$(this).hide().fadeIn('slow');
updateNameAttribute(theCloneId); // need to update the name atribute or validation won't work
}));
formNameIncrement++;
});
clones/add-another-supervisor.tpl
<div class="standard-row add-admin-row input-row">
<label class="ib ib217"> <span class="plain-select">
<select class="inp" data-myname="supervisor[]" name="supervisor[]">
<option value="">Select one</option>
{section name="i" loop=$supervisor}
<option value="{$supervisor[i]->id}">{$supervisor[i]->name}</option>
{/section}
</select>
</span> </label>
<p class="add remove-this-data fl"><i class="sprite delete2"></i> <span> </span></p>
</div>
The only part that is not working is the clones/add-another-supervisor.tpl page doesn't receive the object $supervisor and therefore none of the select options get filled.
Does anyone know how I can fix this?
Update
Tidied up the solution in progress and added some extra details
I have a form area which creates clones based on a template. In order to make sure the form transmits in an order, the script goes through the form at send time appending a number which defines the current batch set. Below is an over simplified representation of what is going on:
<form>
<div class="batch-template">
<div class="batch-piece">
<a class="clone" />
<input name="test-input">
<input name="another-test-input">
<select name="a-drop-down">
</div>
</div>
<div class="batch-paste-area">
</div>
</form>
When the page starts:
The contents of "batch-template" are stored to an object variable
The original template is removed from the page
An instance of the template is appended to the "batch-paste-area"
The following is an example of the output created after clicking twice.
<form>
<div class="batch-template">
</div>
<div class="batch-paste-area">
<div class="batch-piece">
<a class="clone" />
<input name="test-input">
<input name="another-test-input">
<select name="a-drop-down">
</div>
<div class="batch-piece">
<a class="clone" />
<input name="test-input">
<input name="another-test-input">
<select name="a-drop-down">
</div>
</div>
</form>
When it comes to submitting the form: prior to serialization, I would like the script to loop through each "batch-piece" within "batch-paste-area" and add a count value to the end of each form field name. Continuing with the set above, the result (to a browser) would seem like that shown below:
<form>
<div class="batch-template">
</div>
<div class="batch-paste-area">
<div class="batch-piece">
<a class="clone" />
<input name="test-input1">
<input name="another-test-input1">
<select name="a-drop-down1">
</div>
<div class="batch-piece">
<a class="clone" />
<input name="test-input2">
<input name="another-test-input2">
<select name="a-drop-down2">
</div>
</div>
</form>
So far, I can either loop through EVERY input within the paste area or just select the last.
Selecting the last batch-piece is simple:
var intCount = 1;
$('.batch-paste-area .batch-piece').each(function(){
/*
* Would like to be able to loop through form fields here
* Below is an attempt to select all form fields for current set
*/
$(this + ' input, '+ this + ' select').each(function() {
var strName = $(this).attr('name') + intCount;
$(this).attr('name', strName);
});
intCount++;
});
Frustratingly, I had actually tried the correct solution in advance but had forgotten to use the comma at the time!
var intCount = 1;
$('.batch-paste-area .batch-piece').each(function(){
/*
* Would like to be able to loop through form fields here
* Below is an attempt to select all form fields for current set
*/
$(this).find("input, select").each(function() {
var strName = $(this).attr('name') + intCount;
$(this).attr('name', strName);
});
intCount++;
});