I am hoping for some insight on the best way to accomplish the following. I want to create a form that will allow for more fields to be added when a + or add button is clicked. So for example the user would fill out a text field lets call it "Description" and then next to it another field called "Unit number". I want to allow for multiple "Description" and "Unit number" fields without submitting the form after each entry, but for the sake of keeping the site looking "Clean" I don't want there to be several duplicate fields if the user only needs to enter information into one of them. I was thinking about using JavaScript to hide the additional fields by just setting display:none. Is this a good/efficient solution? Is there a better solution? I am new to programming so take it easy if you feel this is a dumb question.
The best way to do this is to make your fields and put them in a div and then hide it. Use jQuery to .clone your first row and then update the field names any time the user clicks an add link.
You can use a templating library like mustache or handlebars. You can also do this using jQuery. My approach would be to generate new elements on the fly. I won't hide it so that the user can see if he is already inputting duplicate. But if you want to make your markup cleaner, you can also hide the field once the user has already inputted something. So when the user clicks on the add button, you will need to check if the user has actually inputted something, if there is an input, then hide it and then generate a new input again.
If you need a code sample, feel free to ask.
Here's some javascript I wrote on my own site awhile ago:
var SITE = SITE || {};
SITE.fileInputs = function() {
var $this = $(this),
$val = $this.val(),
valArray = $val.split('\\'),
newVal = valArray[valArray.length-1],
$button = $this.siblings('.button'),
$fakeFile = $this.siblings('.file-holder');
if(newVal !== '') {
$button.text('File Chosen');
if($fakeFile.length === 0) {
$button.after('<span class="file-holder">' + newVal + '</span>');
} else {
$fakeFile.text(newVal);
}
}
};
var counter = 1;
var limit = 5;
function addInput(divName){
if (counter == limit) {
alert("You have reached the limit of adding " + counter + " inputs");
}
else {
var newdiv = document.createElement('div');
newdiv.innerHTML = "<span class=\"file-wrapper\"><input type=\"file\" name=\"screenshot[]\" id=\"screenshot\" /><span class=\"button\">Choose a screenshot</span></span>";
document.getElementById(divName).appendChild(newdiv);
counter++;
$('.file-wrapper input[type=file]').bind('change focus click', SITE.fileInputs);
}
}
$(document).ready(function(){
$("#addss").click(function(){
addInput("screenshots");
});
});
Then you can just use the array for the name in the php or whatever else you're using to handle the data.
HTML:
<div id="screenshots">
<span class="file-wrapper">
<input type="file" name="screenshot[]" class="screenshot" />
<span class="button">Choose a screenshot</span>
</span>
</div>
<input type="button" id="addss" value="+Screenshot" class="btn" />
Related
I have a form where users can create recipes. I start them off with one ingredient field (among others) and then use .append() to add as many more as they want to the div container that holds the first ingredient. The first input field has an id of IngredientName1 and dynamically added input fields are IngredientName2, IngredientName3, etc.
When they start typing in the input field, I pop a list of available ingredients filtered by the value they key into IngredientNameX. When they click on an ingredient in the list, it sets the value of the IngredientNameX field to the text from the div - like a search & click to complete thing. This all works very well; however, when you add IngredientName2 (or any beyond the one I started them with initially) clicking on an available ingredient sets the values of every single IngredientNameX field. No matter how many there are.
I hope this is enough context without being overly verbose, here's my code (I've removed a lot that is not relevant for the purpose of posting, hoping I didn't remove too much):
<div id="ingredientsContainer">
<input type="hidden" id="ingredientCounter" value="1">
<div class="ingredientsRowContainer">
<div class="ingredientsInputContainer"><input class="effect-1 ingredientsInput" type="text" name="IngredientName1" placeholder="Ingredient" id="IngredientName1" data-ingID="1"><span class="focus-border"></span></div>
</div>
<input type="hidden" name="Ingredient1ID" id="Ingredient1ID">
</div>
<script>
$(document).ready(function(){
$(document).on('keyup', "[id^=IngredientName]",function () {
var value = $(this).val().toLowerCase();
var searchValue = $(this).val();
var valueLength = value.length;
if(valueLength>1){
var theIngredient = $(this).attr("data-ingID");
$("#Ingredients").removeClass("hidden")
var $results = $('#Ingredients').children().filter(function() {
return $(this).text() === searchValue;
});
//user selected an ingredient from the list
$(".ingredientsValues").click(function(){
console.log("theIngredient: "+theIngredient);//LOGS THE CORRECT NUMBER
var selectedIngredientID = $(this).attr("id");
var selectedIngredientText = $(this).text();
$("#IngredientName"+String(theIngredient)).val(selectedIngredientText);//THIS IS WHAT SETS EVERYTHING WITH AN ID OF IngredientNameX
$("#Ingredient"+String(theIngredient)+"ID").val(selectedIngredientID);
$("#Ingredients").addClass("hidden");
});
$("#Ingredients *").filter(function() {
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
});
} else {
$("#Ingredients").addClass("hidden")
}
});
$("#AddIngredient").click(function(){
var ingredientCounter = $("#ingredientCounter").val();
ingredientCounter++;
$("#ingredientCounter").val(ingredientCounter);
$('#ingredientsContainer').append('\
<div class="ingredientsRowContainer">\
<div class="ingredientsInputContainer"><input class="effect-1 ingredientsInput" type="text" name="IngredientName'+ingredientCounter+'" placeholder="Ingredient" id="IngredientName'+ingredientCounter+'" data-ingID="'+ingredientCounter+'"><span class="focus-border"></span></div>\
</div>\
<input type="hidden" name="Ingredient'+ingredientCounter+'ID" id="Ingredient'+ingredientCounter+'ID">\
');
});
});
</script>
[UPDATE] I realized the problem is happening because the function is running multiple times. I assume this happening because I'm calling a function on keyup of a field whose id starts with IngredientName so when one has a key up event, all existing fields run the function. How do i modify my:
$(document).on('keyup', "[id^=IngredientName]",function () {
to only run on the field with focus?
So I am trying to create a function in which I have various checkboxes of territories. The only thing is that I have pages for only some of the territories. So when a user selects a territory and it has a link to a page, then on submit it will take the user to that page. If the checkbox does not have a link then it will go to contact page. But if they select more than one territory and one of them has a link, it should still take them to that same contact page. The second part is that I want the selections to be parsed to the url to go to the contact page which will be a contact form 7 form so it auto fills the territory they selected.
so far I have created a function which recognizes how many checkboxes have been selected. I tried to add links and identify if those links that were selected with the checkbox. Im not sure if it is recognizing it with its corresponding element.
Html
<a href="https://corporate.territory.place/advertising-sandiego"
id="salesURL"><input type="checkbox" name="territories" value="San
Diego, CA">San Diego, CA</a>
<a href="https://corporate.territory.place/advertising-orlando"
id="salesURL"><input type="checkbox" name="territories"
value="Orlando, FL">Orlando, FL</a>
<a href="#" id="nosalesURL"><input type="checkbox"
name="territories" value="Miami, FL">Miami, FL</a><br>
<button onclick="printChecked()">Click here</button>
jquery
function printChecked(){
var items=document.getElementsByName('territories');
/*below list the value of the selections*/
var selectedItems="";
for(var i=0; i<items.length; i++){
if(items[i].type=='checkbox' && items[i].checked==true)
var itemz = selectedItems+=items[i].value+" ";}
var n = $("input[name=territories]:checked").length;/*Counts
number of box selected*/
var salesUrl =
document.getElementById("salesURL").getAttribute("href");
var salesID =
document.getElementById("salesURL").getAttribute('id');
if( n >= 1 && salesID == "salesURL"){
$("#info").html("Selected only 1" + " " + salesUrl+" "+itemz);
}else if(n >= 1 && salesID == "nosalesURL"){
$("#info").html("Go to contact sales");
}else{
$("#info").html("none selected");
}
}
Here's a link to where I am building it out!
For some reason when I try to set the condition for more than one selected it gives me the result of the first condition. I want the function to recognize the checkbox and determine if they have a url. if more than one then go to this page. it only one selected and it has a url then go to another page. etc
Since you only want to use the specific URL if 1 checkbox is checked, you can simplify the logic by only looking for that event. All other scenarios will result in the contact page. Additionally, id should be unique for each element, but they aren't even required here so you should remove them (or make them unique).
I added an additional function for handling the redirects.
JS
<script type="text/javascript">
function printChecked() {
var items = $("input[name=territories]:checked"),
url = "contact.html";
if (items.length == 1) {
var href = items.parent("a").attr("href");
if ($.trim(href).length > 1) {
url = href;
}
}
redirect(url);
}
function redirect(url) {
window.location = url;
}
</script>
This is the solution I arrived at.
$( "#territorybtn" ).click(function() {
var places = $("input[name=territories]:checked");
var clickTerritory = $("input[name=territories]:checked").val();
var clickTerritoryUrl = "https://privatecontractor.com/loaction-"+clickTerritory;
var shortClickTerritoryUrl = clickTerritoryUrl.substr(0,
clickTerritoryUrl.length-2);
var saleID = places.parent("a").attr("class");
/*below list the value of the selections*/
var selectedItems="";
for(var i=0; i<places.length; i++){
if(places[i].type=='checkbox' && places[i].checked==true)
var itemz = selectedItems+=places[i].value+" ";}
/*Conditions*/
if (places.length == 1 && saleID == "salesURL"){
window.location = shortClickTerritoryUrl;
}else if(places.length == 0){
alert(places.length +" "+ "Choose a Territory");
}else{
window.location = "https://privatecontractor.com/contact-sales/?textarea=" + itemz;
}
});
So I am checking to see if the checkboxes are checked and their values. Next, I am looping the values if more than one checkbox is selected so when I parse it to the url for the contact form it will list them in the form.
I placed the condition so that if one checkbox is checked and its parent anchor has the class then it would go to the url created based on its value. If more than one is selected then they will go to contact form with the values added to the url.
For the second part of parsing the checked box values to the url to send to contact form i used a script from this awesome gentleman. https://wplearninglab.com/contact-form-7-get-value-from-url/
Thanks for your help #johnniebenson.
I am trying to build a form using only JavaScript and jQuery. For one of the textboxes, I need to make it display as a date. And another as American Currency.
I have seen a few really cool forms before where it already has the " / /" symbols in there, and as you type the date, it falls perfectly into the symbols so you don't have to type them. Also, I need it to display as a date in the same format (mm/dd/yyyy) when a button is clicked. In addition, somehow, I need it where if no dates were entered, it displays nothing when the button is pushed.
EDIT:
Okay, so, after looking around online, I found a better way to describe what I am looking for for the date. It is exactly the same as the HTML5
<input type="date">
However, after clicking the button, I need it to display as MM/DD/YYYY and the HTML5 only allows YYYY-MM-DD which is NOT what I want.
So, how do I build a single textbox that has the same functions (I don't need the date picker) as the HTML5 "date", but with the display formate as MM/DD/YYYY after a button is clicked?
This sort of input is not trivial. There's some finesse that you'll need to do. First the HTML:
<div id="dateInput">
<input type="number" placeholder="MM" maxlength="2"/>/<input type="number" placeholder="DD" maxlength="2"/>/<input type="number" placeholder="YYYY" maxlength="4"/>
</div>
<div id="moneyInput">
$<input type="number"/>
</div>
Now basic CSS, we'll remove the borders from the inputs and instead add them to the containers:
input{
border:none;
background:transparent;
}
div{
border:1px solid #e0e0e0;
}
Here's the hardest part, the Javascript/jQuery. The money one should work natively but the date one will take some work.
$('#dateInput').on('input', function(){
//get max length of the input
var maxLength = parseInt($(this).attr('maxlength'));
//get the current value of the input
var currentValue = $(this).val();
//if the current value is equal to the maxlength
if(maxLength == currentValue.length){
//move to next field
$(this).next().focus();
};
});
On button press gather all the values from the inputs and display
$('button').on('click', function(e){
e.preventDefault();
//set the variable to append ti
var dateDisplay = '';
//iterate over the inputs
$('#dateInput input').each(function(){
//if dateDisplay exists (will explain soon)
if(dateDisplay && $(this).val() != ''){
//append the value
dateDisplay += $(this).val() + '/';
} else {
//if the value is blank, make the variable false.
dateDisplay = false;
};
});
//now check the variable
if(dateDisplay){
//if it's all good, remove the last character (/) and display
alert(dateDisplay.slice(0,-1));
}
return false;
});
This doesn't check for validity, just handles the general UX.
I was browsing online and in other forums, and found this answer:
$('#date').keyup(function(){
if ($(this).val().length == 2){
$(this).val($(this).val() + "/");
}
else if ($(this).val().length == 5){
$(this).val($(this).val() + "/");
}
});
This is what i have http://jsfiddle.net/bd9wv/... what i am trying to do is have boxes users can input numbers in, and be able to comment back based on the numbers they gave..what i have works for one only...if someone would not mind telling me...what holds the input, i think it's var val? i think i should be able to add more boxes. exp... var al id="number1" type="text"/> ...and then in js..... msg = 'Thank you for the wonderful number: ' + (val+al); but that does not work for me. i would like maybe 10 boxes..but 2-3 is good for me to see how it is done. what i am not understanding is what holds the input and how to use it...explaning a little would be great, i think the submit might be getting me. but if you have an example i can look at it an figure it out,i will be very thankful!!
$('#someButton').click(function () {
var val = $('#inputFieldId').val();
var $outputDiv = $('#outputFieldId');
var msg = '';
if (! $.isNumeric(val)) {
msg = 'Please enter a valid number';
}
else if (parseInt(val, 10) > 100) {
msg = 'Enter number less than 100';
}
else {
msg = 'Thank you for the wonderful number: ' + val;
}
$outputDiv.text(msg);
}
Keeping much of your code in place you can make this work. I changed your ID's to classes, since there will be multiple similar elements. I modified a piece of your JS to the following:
var val = $(this).prev(".number").val();
var $outputDiv = $(this).next().next(".feedback");
Using this you can find the closest elements to the input the user was typing.
And your HTML:
Enter number: <input class="number" type="text"/>
<button class="btnNumber">Submit</button>
<br/>
Feedback: <div class="feedback"></div>
Demo: http://jsfiddle.net/bd9wv/1/
I could not understand clearly; but please try whether this work for you or no http://jsfiddle.net/bd9wv/2/
Example:
var val = $(this).parent().find('.number').val();
Here I have used class and have surround the html block with another div
I am using ASP.Net MVC along with Jquery to create a page which contains a contact details section which will allow the user to enter different contact details:
<div id='ContactDetails'>
<div class='ContactDetailsEntry'>
<select id="venue_ContactLink_ContactDatas[0]_Type" name="venue.ContactLink.ContactDatas[0].Type">
<option>Email</option>
<option>Phone</option>
<option>Fax</option>
</select>
<input id="venue_ContactLink_ContactDatas[0]_Data" name="venue.ContactLink.ContactDatas[0].Data" type="text" value="" />
</div>
</div>
<p>
<input type="submit" name="SubmitButton" value="AddContact" id='addContact' />
</p>
Pressing the button is supposed to add a templated version of the ContactDetailsEntry classed div to the page. However I also need to ensure that the index of each id is incremented.
I have managed to do this with the following function which is triggered on the click of the button:
function addContactDetails() {
var len = $('#ContactDetails').length;
var content = "<div class='ContactDetailsEntry'>";
content += "<select id='venue_ContactLink_ContactDatas[" + len + "]_Type' name='venue.ContactLink.ContactDatas[" + len + "].Type'><option>Email</option>";
content += "<option>Phone</option>";
content += "<option>Fax</option>";
content += "</select>";
content += "<input id='venue_ContactLink_ContactDatas[" + len + "]_Data' name='venue.ContactLink.ContactDatas[" + len + "].Data' type='text' value='' />";
content += "</div>";
$('#ContactDetails').append(content);
}
This works fine, however if I change the html, I need to change it in two places.
I have considered using clone() to do this but have three problems:
EDIT: I have found answers to questions as shown below:
(is a general problem which I cannot find an answer to) how do I create a selector for the ids which include angled brackets, since jquery uses these for a attribute selector.
EDIT: Answer use \ to escape the brackets i.e. $('#id\\[0\\]')
how do I change the ids within the tree.
EDIT: I have created a function as follows:
function updateAttributes(clone, count) {
var f = clone.find('*').andSelf();
f.each(function (i) {
var s = $(this).attr("id");
if (s != null && s != "") {
s = s.replace(/([^\[]+)\[0\]/, "$1[" + count + "]");
$(this).attr("id", s);
}
});
This appears to work when called with the cloned set and the count of existing versions of that set. It is not ideal as I need to perform the same for name and for attributes. I shall continue to work on this and add an answer when I have one. I'd appreciate any further comments on how I might improve this to be generic for all tags and attributes which asp.net MVC might create.
how do I clone from a template i.e. not from an active fieldset which has data already entered, or return fields to their default values on the cloned set.
You could just name the input field the same for all entries, make the select an input combo and give that a consistent name, so revising your code:
<div id='ContactDetails'>
<div class='ContactDetailsEntry'>
<select id="venue_ContactLink_ContactDatas_Type" name="venue_ContactLink_ContactDatas_Type"><option>Email</option>
<option>Phone</option>
<option>Fax</option>
</select>
<input id="venue_ContactLink_ContactDatas_Data" name="venue_ContactLink_ContactDatas_Data" type="text" value="" />
</div>
</div>
<p>
<input type="submit" name="SubmitButton" value="AddContact" id='addContact'/>
</p>
I'd probably use the Javascript to create the first entry on page ready and then there's only 1 place to revise the HTML.
When you submit, you get two arrays name "venue_ContactLink_ContactDatas_Type" and "venue_ContactLink_ContactDatas_Data" with matching indicies for the contact pairs, i.e.
venue_ContactLink_ContactDatas_Type[0], venue_ContactLink_ContactDatas_Data[0]
venue_ContactLink_ContactDatas_Type[1], venue_ContactLink_ContactDatas_Data[1]
...
venue_ContactLink_ContactDatas_Type[*n*], venue_ContactLink_ContactDatas_Data[*n*]
Hope that's clear.
So, I have a solution which works in my case, but would need some adjustment if other element types are included, or if other attributes are set by with an index included.
I'll answer my questions in turn:
To select an element which includes square brackets in it's attributes escape the square brackets using double back slashes as follows: var clone = $("#contactFields\[0\]").clone();
& 3. Changing the ids in the tree I have implemented with the following function, where clone is the variable clone (in 1) and count is the count of cloned statements.
function updateAttributes(clone, count) {
var attribute = ['id', 'for', 'name'];
var f = clone.find('*').andSelf();
f.each(function(i){
var tag = $(this);
$.each(attribute, function(i, val){
var s = tag.attr(val);
if (s!=null&& s!="")
{
s = s.replace(/([^\[]+)\[0\]/, "$1["+count+"]");
tag.attr(val, s);
}
});
if ($(this)[0].nodeName == 'SELECT')
{ $(this).val(0);}
else
{
$(this).val("");
}
});
}
This may not be the most efficient way or the best, but it does work in my cases I have used it in. The attributes array could be extended if required, and further elements would need to be included in the defaulting action at the end, e.g. for checkboxes.