Show Character Limit From Textarea On Cloned Row - javascript

[EDIT] Revising original question for better clarity
This section of this form allows the user to add as many rows as necessary, and works. My problem is that I cannot figure out how to make the character count work on the textarea of the cloned rows.
(Thanks to zer00ne for the all the awesome help here. Great, concise coding! Also provided a jQuery character count in a fraction of lines compared to my former Javascript code.)
Here's a fiddle: https://jsfiddle.net/RationalRabbit/2vmqk26b/4/
CSS
textarea,
output,
button {font-size:inherit;}
output:nth-of-type(n+2) {margin-left:3px;}
.msg {border:none;}
.clearfix:before,
.clearfix:after {display:table; content: "";}
.clearfix:after {clear:both;}
.RowDeleteButton {float:right; font-family:arial, sansserif; font-size:14px; display:inline-block; text-decoration:none; color:#AC0F0F; font-weight:900; cursor:pointer;}
.RowDeleteButton:hover, .RowDeleteButton:focus {color:#FF0000;}
HTML
<fieldset>
<div class="parent-group">
<div class="form-group">
<input id="Name" name="Name[]" size="20" value="" />
<input type="checkbox" id="HM" name="HM[]" value="X" />
<textarea class="txt" id="TA" rows="1" cols="30" name="TA[]" maxlength="100"></textarea>
<input class='msg' name="Output" id="Output" size="3" readonly value="100" />
<input type="text" name="Location[]" id="Location" size="30" value="" />
<div class="form-group RowDelete">
<a class="RowDeleteButton" id="DeleteRow" href="javascript:void(0)"> X </a>
</div>
<div class="Clear"></div>
</div>
</div>
<div class="clearfix"></div>
<div id="container"></div>
<div class="form-group">
<a id="AddRow" href="javascript:void(0)"><span style="color:#0F61AC;">Add Row</span></a>
</div>
</fieldset>
jQuery
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
// onkeyup invoke charCount
$('.txt').on('keyup', charCount);
// onclick...
$('#DeleteRow').closest('.form-group').hide();
$('#AddRow').on('click', function (e)
{
var len = $('.child-border').length;
$('.parent-group').clone(true, false).find(':input').each(function (idx, ele)
{
ele.name = ele.name + len;
ele.id = ele.id + len;
ele.value = '';
}).end().find('.form-group').toggle(true).end()
.toggleClass('parent-group child-border').hide()
.appendTo('#container').slideDown('slow');
});
$('#container').on('click', '[id^=DeleteRow]', function(e)
{
var jsonData = $(this).closest('.child-border, .parent-group')
.find(':input:not(button)').get()
.reduce(function (acc, ele)
{
acc[ele.name || ele.id] = ele.value;
return acc;
}, {});
$(this).closest('.child-border, .parent-group').remove();
console.log(jsonData);
});
function charCount(e)
{
// Get the text
var chars = this.value;
// Get maxlength as a number
var charMax = Number(this.getAttribute('maxlength'));
// Number of chars typed
var charDone = chars.length;
// Chars remaining is 100 - chars typed
var charToGo = charMax - charDone;
// Display chars remaining
$(this).next('.msg').val(charToGo);
}
</script>

2nd Update
I already said what the issue was in Update 1:
$('.parent-group').clone(true, false).find(':input')
🔺
The second parameter should be true
This will allow the clone() method to keep registered events on the clone. Notice I had said the same thing on the 1st Update, but I failed to change the code in Demo 2.
Demo 3 is a heavy modification of the most currently updated OP code. It is fully functional and it retains registered events on clones just like Demo 2. Added features are: local/sessionStorage, sends data to a live test server, and displays server response.
Demo 4 is OP code and one simple change...want to take a wild guess as to what that might be?.
1st Update
When cloning, use the first parameter to determine whether the clone keeps the registered event handlers the original node has.
$('#original').clone(true, true);
See Demo 2
Not sure what you mean by "one row". This demo is streamlined compared to OP code. I added auto height instead of cloning rows.
Details commented in demo
Demo 1
// On keyup...
$('#txt').on('keyup', function() {
// Get the text
var chars = this.value;
// if there are any linebreaks...
if (chars.match(/\n/g)) {
/* The value of rows attribute equals
|| the number of line breaks +2
*/
this.rows = chars.match(/\n/g).length + 2;
}
/* Get value of maxlength attribute convert
|| to number
*/
var charMax = Number(this.getAttribute('maxlength'));
// Number of chars typed
var charDone = chars.length;
// Chars remaining is 100 - chars typed
var charToGo = charMax - charDone;
// Display chars remaining
$('#msg').val(charToGo + ' characters remaining');
});
<textarea id='txt' rows="1" cols="30" maxlength="100"></textarea><br>
<output id='msg' for='txt'></output>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Demo 2
// onkeyup invoke charCount
$('.txt').on('keyup', charCount);
// onclick...
$('button').on('click', function() {
/* clone the first .txt and .msg
|| true: keep registered events
|| false: copy content
|| set .val('') to blank
|| add to fieldset
*/
$('.txt:first').clone(true, true).val('').appendTo('fieldset');
$('.msg:first').clone(true, true).val('').appendTo('fieldset');
});
function charCount(e) {
// Get the text
var chars = this.value;
// Get maxlength as a number
var charMax = Number(this.getAttribute('maxlength'));
// Number of chars typed
var charDone = chars.length;
// Chars remaining is 100 - chars typed
var charToGo = charMax - charDone;
// Display chars remaining
$(this).next('.msg').val(charToGo + ' characters remaining');
}
textarea,
output,
button {
font-size: inherit
}
output {
display: inline-block;
vertical-align: top;
}
output:nth-of-type(n+2) {
margin-left: 3px
}
button {
margin-left: 90%
}
<button type='button'>Add</button>
<fieldset>
<textarea class='txt' rows="1" cols="30" maxlength="100"></textarea>
<output class='msg'></output>
</fieldset>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Demo 3
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1, user-scalable=no">
<title></title>
<style>
textarea,
output,
button {
font-size: inherit;
}
output:nth-of-type(n+2) {
margin-left: 3px;
}
.msg {
border: none;
}
.clearfix:before,
.clearfix:after {
display: table;
content: "";
}
.clearfix:after {
clear: both;
}
.del {
float: right;
margin-top: .5px;
font-family: arial, sansserif;
font-size: 14px;
display: inline-block;
text-decoration: none;
color: #AC0F0F;
font-weight: 900;
cursor: pointer;
}
.del:hover,
.del:focus {
color: #FF0000;
}
main {
display: table;
}
</style>
<script>
/* Global counter variable */
var counter = 0;
</script>
</head>
<body>
<main class="main-group">
<!--This form submits to a live test server, the [target] attribute value
is that of an iframe's name attribute. By targeting the iframe the
form can display the test server's response in the iframe
-->
<form id='main' action='https://httpbin.org/post' method='post' target='response'>
<!--The original fieldset is cloned-->
<fieldset id='set' class="form-group">
<button id="del" class='ui del' type='button'> X </button>
<input id='ID' name='ID' class='data' type='hidden'>
<input id="name" name="name" class='data name' size="25">
<input id="chx" name="chx" class='data chx' type="checkbox" value="X">
<br>
<textarea id="txt" name="txt" class='data txt' rows="1" cols="30" maxlength="100"></textarea>
<output class='ui msg'></output>
<br>
<input id="loc" name="loc" class='data loc' size="30">
</fieldset>
</form>
<nav class="btn-group">
<a id="add" href="#/" class='ui'> <b style="color:#0F61AC;">Add Row</b> </a>
<!--This submit button must use the [form] attribute with the ID of the
form to be accociated with-->
<input type='submit' form='main' class='ui'>
</nav>
<iframe src='about:blank' name='response' class='ui'></iframe>
</main>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>
// Click...
$('#add').on('click', function(e) {
// Increment counter
counter++;
/* clone fieldset#set true: clone descendants /
|| TRUE: KEEP EVENTS ON CLONES
|| Gather all of the .data in clone then on each clone...
*/
var dupe = $('#set').clone(true, true);
dupe[0].id = 'set' + counter;
dupe.find('.data').each(function(idx, ele) {
// Set all .data with name and id, the counter suffix makes them unique
ele.name = this.name + counter;
ele.id = this.id + counter;
// Clear all data in each .data
ele.value = '';
// Cool animation and append clone to form#main
}).end().find('.form-group').toggle(true).end().hide().appendTo('#main').slideDown('slow');
// Clear .ui of data
dupe.find('output').val('');
dupe.find(':checkbox').prop('checked', false);
});
// Clicking any button.del...
$('.del').on('click', function(e) {
// Define arrays
var jsonData = [];
var JSONKeys = [];
// This collects all accossiated .data of ,del
var dataRow = $(this).nextAll('.data').toArray();
// This map() will create an object literal and add it to an array
jsonData = dataRow.map(function(data, idx) {
var D = {};
D.k = data.id;
D.v = data.value;
return D;
});
console.log(jsonData);
// Proceedure to timestamp data
var stamp = new Date();
var jKey = stamp.toJSON();
// Fill an array of keys for future reference
JSONKeys.push(jKey);
/* Store JSON data in sessionStorage (can be localStorage also) */
setData(jKey, jsonData);
// Save an index of the jsondata
setData('JSONKeys', jKey);
// if there's only one fieldset, reset the form if user tries to delete it
if ($('fieldset').is(':only-child')) {
$('#main')[0].reset();
} else {
// Remove fieldset
$(this).parent('.form-group').remove();
}
});
// onkeyup invoke charCount
$('.txt').on('keyup', charCount);
function charCount(e) {
// Get the text
var chars = this.value;
// Get maxlength as a number
var charMax = Number(this.getAttribute('maxlength'));
// Number of chars typed
var charDone = chars.length;
// Chars remaining is 100 - chars typed
var charToGo = charMax - charDone;
// Display chars remaining
$(this).next('.msg').val(charToGo);
}
function setData(dataKey, dataVal) {
sessionStorage.setItem(dataKey, JSON.stringify(dataVal));
}
function getData(dataKey) {
return JSON.parse(sessionStorage.getItem(dataKey));
}
</script>
</body>
</html>
Demo 4
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1, user-scalable=no">
<title></title>
</head>
<body>
<fieldset>
<div class="parent-group">
<div class="form-group">
<input id="Name" name="Name[]" size="20" value="" />
<input type="checkbox" id="HM" name="HM[]" value="X" />
<textarea class="txt" id="TA" rows="1" cols="30" name="TA[]" maxlength="100"></textarea>
<input class='msg' name="Output" id="Output" size="3" readonly value="100" />
<input type="text" name="Location[]" id="Location" size="30" value="" />
<div class="form-group RowDelete">
<a class="RowDeleteButton del" href="javascript:void(0)"> X </a>
</div>
<div class="Clear"></div>
</div>
</div>
<div class="clearfix"></div>
<div id="container"></div>
<div class="form-group">
<a id="AddRow" href="javascript:void(0)"><span style="color:#0F61AC;">Add Row</span></a>
</div>
</fieldset>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
// onclick...
$('#DeleteRow').closest('.form-group').hide();
$('#AddRow').on('click', function(e) {
var len = $('.child-border').length;
$('.parent-group').clone(true, true).find(':input').each(function(idx, ele) {
ele.name = ele.name + len;
ele.id = ele.id + len;
ele.value = '';
}).end().find('.form-group').toggle(true).end()
.toggleClass('parent-group child-border').hide()
.appendTo('#container').slideDown('slow');
});
$('.del').on('click', function(e) {
var jsonData = $(this).closest('.child-border, .parent-group')
.find(':input:not(button)').get()
.reduce(function(acc, ele) {
acc[ele.name || ele.id] = ele.value;
return acc;
}, {});
$(this).closest('.child-border, .parent-group').remove();
console.log(jsonData);
});
function charCount(e) {
// Get the text
var chars = this.value;
// Get maxlength as a number
var charMax = Number(this.getAttribute('maxlength'));
// Number of chars typed
var charDone = chars.length;
// Chars remaining is 100 - chars typed
var charToGo = charMax - charDone;
// Display chars remaining
$(this).next('.msg').val(charToGo);
}
// onkeyup invoke charCount
$('.txt').on('keyup', charCount);
</script>
</body>
</html>

Using zer00ne's Demo 4, this is what I finally came up with. the differences are:
1. Set the first working row as array for database insert using regex. Also designated unique row input id's using parentheses.
2. Set delete button so that it does not appear on first row.
3. My script sets a max number of rows (8).
4. Global variable used to hold row count. Important in the event that the user deletes a row or rows in the middle of the set, then adds rows below.
5. Set checkbox so that the value is kept in cloned rows. "checked" set to false.
The PHP shows how I handled the array server-side so that I come out with arrays in numerical order. This could probably be handled differently, but worked for me. Without using the LastArrayValue variable to handle the last array value, and the ChildCount variable, which says how many rows there actually are, if you delete, for instance, rows 2 & 3 out of eight, you would only have 6 rows, but not be allowed to add additional. Also, without those variables, when rows are deleted in the middle, you will end up with duplicate array keys. This becomes even more critical when you have a max number of rows to deal with.
https://jsfiddle.net/uyz2zjj6/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1, user-scalable=no">
<title></title>
<style type="text/css">
textarea,
output,
button {font-size:inherit;}
output:nth-of-type(n+2) {margin-left:3px;}
.msg {border:none;}
.clearfix:before,
.clearfix:after {display:table; content: "";}
.clearfix:after {clear:both;}
.RowDeleteButton {float:right; font-family:arial, sansserif; font-size:14px; display:inline-block; text-decoration:none; color:#AC0F0F; font-weight:900; cursor:pointer;}
.RowDeleteButton:hover, .RowDeleteButton:focus {color:#FF0000;}
</style>
</head>
<body>
<fieldset>
<div class="parent-group">
<div class="form-group">
<input id="Name(0)" name="Name[0]" size="20" value="" />
<input type="checkbox" id="HM(0)" name="HM[0]" value="X" />
<textarea class="txt" id="TA(0)" rows="1" cols="30" name="TA[0]" maxlength="100"></textarea>
<input class='msg' name="Output" id="Output(0)" size="3" readonly value="100" />
<input type="text" name="Location[0]" id="Location(0)" size="30" value="" />
<div class="form-group" style="display:inline-block;">
<a class="RowDeleteButton del" id="DeleteRow" href="javascript:void(0)"> X </a>
</div>
<div class="Clear"></div>
</div>
</div>
<div class="clearfix"></div>
<div id="container"></div>
<div class="form-group">
<a id="AddRow" href="javascript:void(0)"><span style="color:#0F61AC;">Add Row</span></a>
</div>
</fieldset>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
// onclick...
window.LastArrayValue = 0;
$('#DeleteRow').closest('.form-group').hide();
$('#AddRow').on('click', function(e)
{
var ChildCount = $('.child-group').length;
if(ChildCount == 7)
{
alert("Sorry, 8 is the maximum number of rows");
}
else
{
var len = window.LastArrayValue;
window.LastArrayValue = len + 1;
$('.parent-group').clone(true, true).find(':input').each(function(idx, ele)
{
var ename = ele.name;
var eid = ele.id
var ArrayValue = len+1;
ele.name = ename.replace(/(\[\/?[^\]]*\])/g, "["+ArrayValue+"]");
ele.id = eid.replace(/(\(\/?[^\]]*\))/g, "("+ArrayValue+")");
if(ele.type == "checkbox"){ele.checked = false;}
else{ele.value = '';}
}).end().find('.form-group').toggle(true).end()
.toggleClass('parent-group child-group').hide()
.appendTo('#container').slideDown('slow');
}
});
$('.del').on('click', function(e)
{
var jsonData = $(this).closest('.child-group, .parent-group')
.find(':input:not(button)').get()
.reduce(function(acc, ele)
{
acc[ele.name || ele.id] = ele.value;
return acc;
}, {});
$(this).closest('.child-group, .parent-group').remove();
console.log(jsonData);
});
function charCount(e)
{
// Get the text
var chars = this.value;
// Get maxlength as a number
var charMax = Number(this.getAttribute('maxlength'));
// Number of chars typed
var charDone = chars.length;
// Chars remaining is 100 - chars typed
var charToGo = charMax - charDone;
// Display chars remaining
$(this).next('.msg').val(charToGo);
}
// onkeyup invoke charCount
$('.txt').on('keyup', charCount)
</script>
</body>
</html>
PHP
// Get the last key number in the array in the event that rows were deleted
// TA is the only required field. If that field is not filled, the row is ignored
end($_POST['TA']); // move the internal pointer to the end of the array
$key = key($_POST['TA']); // fetches the key of the element pointed to by the internal pointer
$Ct = $key+1; // account for array start at 0
reset($_POST['TA']); // Reset the array back to the top for processing.
$j=0; // Count only if TA has a value (revaluate $Ct when complete for later use ($Ct = $j))
for($i=0;$i<$Ct;$i++)
{
if(empty($_POST['TA'][$i])) // Empty may be that field is empty or there is no such row.
{
continue;
}
$Name[$j] = $_POST['Name'][$i];
$HM[$j] = $_POST['HM'][$i];
$TA[$j] = $_POST['TA'][$i];
$Location[$j] = $_POST['Location'][$i];
$j++;
}
$Ct = $j; // $Ct now holds the number of records and those records are in numerical order, 1-8

Related

Multiply output by inputs

I'm trying to create a list based off of 2 input fields. The first input will be a name and the second an integer.
What I'm trying to achieve is having the name displayed multiplied by the amount of the input integer. I have got the name to display based off the input, but have been unable to have it displayed multiple times based on the input integer.
Here's an example image of what I'm looking to achieve
<html>
<head>
<style>
input {
display: block;
}
#msgs {
margin-bottom: 24px;
}
</style>
<meta charset="utf-8">
<title>Test</title>
</head>
<body>
<input type="text" value="Michael" id="name" />
<input type="text" value="5" id="count" />
<input type="button" value="add to list" id="add" />
<div id="list"> </div>
</body>
<script>
document.getElementById("add").onclick = function() {
var text = document.getElementById("name").value;
var div = document.createElement("div");
div.textContent = text;
document.getElementById("list").appendChild(div);
document.getElementById("name").value = ""; // clear the value
}
</script>
</html>
Fiddle: https://jsfiddle.net/grnct2yz/
<html>
<head>
<style>
input {
display: block;
}
#msgs {
margin-bottom: 24px;
}
</style>
<meta charset="utf-8">
<title>Test</title>
</head>
<body>
<input type="text" value="Michael" id="name" />
<input type="number" value="5" id="count" />
<input type="button" value="add to list" id="add" />
<div id="list"> </div>
</body>
<script>
document.getElementById("add").onclick = function() {
var text = document.getElementById("name").value;
for(let i = 0; i < document.getElementById("count").value; i++) {
var div = document.createElement("div");
div.textContent = text;
document.getElementById("list").appendChild(div);
}
document.getElementById("name").value = ""; // clear the value
}
</script>
</html>
I have added a loop and changed the input type to number so we are sure that it's going to insert a number in the loop. Is this what you wanted?
What the code I added does is cycling a number of times equal to the number inputted and then executing the code you wrote.
for loops work this way:
you set an initial statement that is executed at the beginning of the loop, only once (let i = 0 sets a new iterable variable i),
then you set a condition that is checked before every iteration of the loop to make it run (i < document.getElementById("count").value checks that it executes up to and not more than X times, where X is the number inputted),
then you set an operation to be executed at the end of each loop (i++ increments the value of i by one).
Here is another way of doing it:
const name=document.getElementById("name"),
count=document.getElementById("count"),
list=document.getElementById("list");
document.getElementById("add").onclick = function() {
list.insertAdjacentHTML("beforeend",[...Array(+count.value)].map(s=>`<div>${name.value}</div>`).join(""))
name.value = ""; // clear the value
}
<input type="text" value="Michael" id="name" /><br>
<input type="text" value="5" id="count" /><br>
<input type="button" value="add to list" id="add" />
<div id="list"> </div>
Just your Improved code based on your needs we can achieve this in many ways.
<html>
<head>
<style>
input {
display: block;
}
#msgs {
margin-bottom: 24px;
}
</style>
<meta charset="utf-8">
<title>Test</title>
</head>
<body>
<input type="text" value="Michael" id="name" />
<input type="text" value="5" id="count" />
<input type="button" value="add to list" id="add" />
<div id="list"> </div>
<script>
document.getElementById("add").onclick = function() {
var text = document.getElementById("name").value;
var count = document.getElementById("count").value;
if (parseInt(count) != 'NaN') {
var list = document.getElementById("list");
while (list.firstChild) {
list.removeChild(list.firstChild);
}
count = parseInt(count);
for (var i = 0; i < count; i++) {
var div = document.createElement("div");
div.textContent = text;
document.getElementById("list").appendChild(div);
}
}
}
</script>
</body>
</html>

How do I make a dynamic drop down menu using JavaScript

I have it so you type in on a form a maximum number then it creates a table after clicking a button.
I want it so after you click the button to add the row it writes a drop down menu in the table that goes from 0 to the number you put in the form
This is my HTML code:
<html>
<head>
<title>Form Generator</title>
<link rel="stylesheet" type="text/css" href="../css/converter.css"/>
<script language="JavaScript" src="../js/exercise2.js" type="text/javascript">
</script>
</head>
<body>
<p>
<button class="button" data-modal="M2KM">Form Generator</button>
</p>
<div id="M2KM" class="modal">
<div class="modal-content">
<div class="form">
<a class="close">×</a>
<form action="">
<textarea rows="1" name="Section" id="Section" cols="10">Section</textarea>
<textarea rows="1" name="Max" id="Max" cols="10">Max</textarea>
<textarea rows="1" name="Comment" id="Comment" cols="10">Comment</textarea>
<textarea rows="1" name="Mark" id="Mark" cols="10">Mark</textarea>
<input type="button" value="Add Row" name="Add Row" onclick="conversionTable('table')" />
<input type="reset" value="Clear" name="Clear">
</form>
<div id="conversion">
<table id="table">
<thead>
<tr>
<th>Section</th>
<th>Max</th>
<th>Comment</th>
<th>Mark</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</body>
</html>
This is my JavaScript Code:
function conversionTable(tagId, from, to)
{
var section = document.getElementById("Section").value;
var max = document.getElementById("Max").value;
var comment = document.getElementById("Comment").value;
var mark = document.getElementById("Mark").value;
from = 0;
to = 1;
var total = 0;
var arr = [];
var conv = document.getElementById(tagId) ;
var pre = document.createElement("pre");
conv.appendChild(pre);
var body= conv.appendChild(document.createElement("tbody"));
for (var i=from; i<to; i++)
{ row = body.appendChild(document.createElement("tr"));
var data=row.appendChild(document.createElement("td"));
data.appendChild(document.createTextNode(section));
data=row.appendChild(document.createElement("td"));
data.appendChild(document.createTextNode(max));
var data=row.appendChild(document.createElement("td"));
data.appendChild(document.createTextNode(comment));
data=row.appendChild(document.createElement("select"));
data.setAttribute("id", "mySelect");
row.appendChild(data);
var z = document.createElement("option");
z.setAttribute("value", "volvocar");
var t = document.createTextNode("1");
z.appendChild(t);
document.getElementById("mySelect").appendChild(z);
total = total + mark;
var obj = {section: section, max: max, comment: comment, mark: mark};
arr.push(obj);
}
}
This is a screenshot showing test data:
Here's a simplified example that adds a select element with a number of options equal to the number entered by the user.
See comments in the code for an explanation of how it works.
// Identifies existing HTML elements
const maxInput = document.getElementById("max");
const button = document.getElementById("button");
const table = document.getElementById("table");
// Calls `addDropdown` when `button` is clicked
button.addEventListener("click", addDropdown);
// Defines the event listener
function addDropdown(event) { //(`event` object is available if we want it)
// Gets value from input
let max = parseInt(maxInput.value);
// Exits function early if maxInput doesn't have a number
if(!max){ return; }
// Defines the new elements
const row = document.createElement("tr");
const cell = document.createElement("td");
const dropdown = document.createElement("select");
// Enumerates options and adds them to the select element
let optNumber = -1;
while(++optNumber <= max){
let optionElement = document.createElement("option");
optionElement.value = "opt" + optNumber;
optionElement.innerHTML = "Option " + optNumber;
dropdown.appendChild(optionElement);
}
// Adds the elements to the page
cell.appendChild(dropdown);
row.appendChild(cell);
table.appendChild(row);
}
<label>
<span>Enter maximum value for dropdown:</span>
<input id="max" value="5" />
</label>
<br />
<button id="button">Add Dropdown in New Row</button>
<div id="container">
<table id="table"></table>
</div>

How to write a character where the cursor is with a virtual keyboard?

I'm working on a live HTML editor. It's basically for mobile users. So I've made a virtual keyboard that has the HTML tags. However, I'm facing a problem:
the keyboard only prints the tags at the end of another tag. So it isn't working as I want it to be.
Here is the code.
(function() {
'use strict';
var i, c, t, delay = 5000,
kb = document.getElementById('keyboard');
/* get all the input elements within the div whose id is "keyboard */
i = kb.getElementsByTagName('input');
/* loop through all the elements */
for (c = 0; c < i.length; c++) {
/* find all the the input type="button" elements */
if (i[c].type === 'button') {
/* add an onclick handler to each of them and set the function to call */
i[c].addEventListener('onclick', makeClickHandler(c));
}
}
/* this is the type="reset" input */
document.getElementById('clear').addEventListener('click',
function() {
/* remove all the characters from the input type="text" element */
document.getElementById('text').value = '';
}, false);
function makeClickHandler(c) {
i[c].onclick = function() {
/* find the non-text button which has an id */
if (i[c].id === 'back') {
/* remove last character from the input the type="text" element using regular expression */
document.getElementById('text').value =
document.getElementById('text').value.replace(/.$/, '');
}
/* find the text buttons */
else {
/* add characters to the input type="text" element */
document.getElementById('text').value += this.value.toLowerCase();
}
};
}
document.onmousemove = resetTimer;
document.onkeypress = resetTimer;
function logout() {
kb.classList.remove('show');
kb.classList.add('hide');
}
function resetTimer() {
clearTimeout(t);
t = setTimeout(logout, delay)
}
resetTimer();
})();
<div id="keyboard" class="show">
<div>
<input type="button" value="Q">
<input type="button" value="W"> .........
<input type="button" value="V">
<input type="button" value="B">
<input type="button" value="N">
<input type="button" value="M">
</div>
<div>
<input id="back" type="button" value="←">
<input id="space" type="button" value=" ">
<input id="clear" type="reset" value="clear">
</div>
<div>
<label>Track Search</label> - <input id="text" type="text">
</div>
<!-- #keyboard -->
</div>
With this code, I can only print after the last printed character. But I want it like so (| means the cursor position),
An|ant
Here I wrote An before ant.
But it prints it like this:
ant An|
What can I do to solve the problem?
I guess what you search for is selectionStart You can use it in major browsers
so you get the start point(and not simply append to the end of the string) of where to add in your
.value += this.value.toLowerCase();
you can simply use it like this:
var input = document.getElementById('text');
var caretPosition = input.selectionStart;
// Check if there is a Selection in your input
if (input.selectionStart != input.selectionEnd)
{
var selectionValue =
input.value.substring(input.selectionStart, input.selectionEnd);
}

How to get the values of all input fields jQuery

So i have a program where it starts off with one input field, and if you press the plus button it adds new input field. I also have it so it gives the new input field a different id. I would prefer it so when i press calculate, it saves the values of all the input fields data into an array. I have tried using a for loop with .val(), but that didnt work.
Code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<title></title>
</head>
<body>
<!-- ************where the input fields are*******-->
<div id="append">
<p style="display:inline-block; margin-bottom:0px;">
<input type='text' class='minutes' id="minute1"/>
<input type='text' class='vidseconds' id="second1"/>
</p>
<div id="plusnminus">
<button id="plus">+</button>
<button id="minus">-</button>
</div>
</div>
<!-- when this is pressed i want it to save the input fields data-->
<p id="calculate">Calculate</p>
</body>
</html>
//JavaScript
$(document).ready(function(){
var mins = [];
//where it add the new input field
var idnum = 1;
$("#plus").click(function(){
idnum+=1;
var input = "<p><input type='text' class='minutes' id='minute"+idnum+"' /><input type='text' class='vidseconds' id='second"+idnum+"'/></p>";
$(input).appendTo("#append");
});
// to remove an input field
$("#minus").click(function(){
if(idnum >= 2){
$("#minute" + idnum+ ", #second" + idnum).remove();
idnum-=1;
}
});
// i want it to put all of the data from the input fields in an array in that click function
$("#calculate").click(function(){
});
});
/*StyleSheet */
#append {
display: inline-block;
}
#plusnminus {
display: inline-block;
}
button {
border-style: none;
background-color: #C0C0C0;
width: 24px;
height: 24px;
}
Everything is inline because i'm trying to keep it a single file. I have placed comments however for readability.
You can use $.map(), selectors #append input[id^=minute], #append input[id^second] to get all input elements that are descendants of #append element; return an array containing two arrays of values, utilize destructuring assignment to set variable identifiers; for example, minutes, seconds, for arrays corresponding to .value of element where id begins with "minute" or "second"
$(document).ready(function() {
var mins = [];
//where it add the new input field
var idnum = 1;
$("#plus").click(function() {
idnum += 1;
var input = "<p><input type='text' class='minutes' id='minute"
+ idnum
+ "' /><input type='text' class='vidseconds' id='second"
+ idnum
+ "'/></p>";
$(input).appendTo("#append");
});
// to remove an input field
$("#minus").click(function() {
if (idnum >= 2) {
$("#minute" + idnum + ", #second" + idnum).remove();
idnum -= 1;
}
});
// i want it to put all of the data
// from the input fields in an array
// in that click function
$("#calculate").click(function() {
var [minutes, seconds] = $.map([$("#append input[id^=minute]")
, $("#append input[id^=second]")]
, function(el) {
return [$.map(el, function(elem) {
return elem.value;
})]
});
// do stuff with `minutes`, `seconds` variables
console.log("minutes:", minutes, "seconds:", seconds);
});
});
#append {
display: inline-block;
}
#plusnminus {
display: inline-block;
}
button {
border-style: none;
background-color: #C0C0C0;
width: 24px;
height: 24px;
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<title></title>
</head>
<body>
<!-- ************where the input fields are*******-->
<div id="append">
<p style="display:inline-block; margin-bottom:0px;">
<input type='text' class='minutes' id="minute1" />
<input type='text' class='vidseconds' id="second1" />
</p>
<div id="plusnminus">
<button id="plus">+</button>
<button id="minus">-</button>
</div>
</div>
<!-- when this is pressed i want it to save the input fields data-->
<p id="calculate">Calculate</p>
</body>
</html>
You can alternatively substitute Array.from() for $.map()
var [minutes, seconds] = Array.from([$("#append input[id^=minute]")
, $("#append input[id^=second]")]
, function(el) {
return Array.from(el, function(elem) {
return elem.value;
});
});
If you wrap your input fields in a form, you can use .serialize() or .serializeArray() to serialize the whole form at once.
$(function() {
$('#my-button').on('click', function() {
var values = $('#my-form').serializeArray();
console.log(values);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="my-form">
<input type="text" name="input1" value="first field"><br/>
<input type="text" name="input2" value="second field"><br/>
<input type="text" name="input3" value="third field"><br/>
</form>
<button id="my-button">Get All Values</button>

JavaScript - display keys and values of an array

I'm playing with a module object and trying to create a sort of blog (it's not going to be used in real life - just me learning stuff).
When a user fills a form and provides a tag, it checks whether the tag exists in an associative array, if not, it adds it with the value = 1. If the tag already exists, it adds +1 to the value. Now I want to display on a side how many entries for each tag there are, eg:
cooking(3)
sport(1)
It seems to partially work as when I add another tag, it displays in but keeps increasing the count of ALL the categories/tags:
cooking(1)
sport(1)
then
cooking(2)
sport(2)
...not just the one the user has just added.
var myArticles = (function () {
var s, articles;
return {
settings: {
articleList: "articles", // div with generated articles
articleClass: "article", // class of an article
articleIndex: 0,
sidebar: document.getElementById("sidebar"),
tagList: {},
// cats: Object.keys(this.settings.tagList)
},
init: function() {
// kick things off
s = this.settings;
articles = document.getElementById(this.settings.articleList);
this.createArticle();
},
createArticle: function() {
var div = document.createElement("div");
var getTag = document.getElementById("tag").value;
var getTitle = document.getElementById("title").value;
// Add classes
div.classList.add(this.settings.articleClass, getTag);
// Add title / content
var title = document.createElement("h2");
var textNode = document.createTextNode(getTitle);
title.appendChild(textNode);
div.appendChild(title);
// Add category
div.innerHTML += "Article" + this.settings.articleIndex;
articles.appendChild(div);
this.settings.articleIndex +=1;
this.updateCategories(getTag);
},
updateCategories: function(tag) {
// Create header
this.settings.sidebar.innerHTML = "<h3>Categories</h3>";
// Create keys and count them
if (tag in this.settings.tagList) {
this.settings.tagList[tag] += 1;
} else {
this.settings.tagList[tag] = 1;
}
var cats = Object.keys(this.settings.tagList);
// Create an unordered list, assign a class to it and append to div="sidebar"
var ul = document.createElement('ul');
ul.classList.add("ul-bare");
this.settings.sidebar.appendChild(ul);
// iterate over the array and append each element as li
for (var i=0; i<cats.length; i++){
var li=document.createElement('li');
ul.appendChild(li);
li.innerHTML=cats[i] + "(" + this.settings.tagList[tag] + ")";
}
}
};
}());
And HTML:
<body>
<div id="container">
<h1>My articles</h1>
<div id="genArticle" class="left">
<form id="addArt" method="post">
<div>
<label for="title">Title</label>
<input type="text" id="title" class="forma" placeholder="Title" required />
</div>
<div>
<label for="tag">Tag</label>
<input type="text" id="tag" class="forma" placeholder="Tag" required />
</div>
<div>
<label for="art">Article</label>
<textarea id="art" class="forma" required /></textarea>
</div>
<input type="button" onclick="myArticles.init()" value="Add Art">
<input type="reset" value="Reset Form">
<input type="range" size="2" name="satisfaction" min="1" max="5" value="3">
</form>
<div id="articles"></div>
</div> <!-- end of genArticle -->
<aside id="sidebar" class="right">
</aside>
</div> <!-- end of container -->
<script src="js/script.js"></script>
</body>
I think this line is wrong
li.innerHTML=cats[i] + "(" + this.settings.tagList[tag] + ")";
It is this.settings.tagList[cats[i]]
Not this.settings.tagList[tag]

Categories

Resources