My input string values will not display on my list - javascript

I want display items of an array. At the click of button I need to perform following actions:
Add an element at the beginning, end or middle of the displayed array
Sort the array
Remove duplicates from array
I managed to display the items of the array, and add new items, one by one with my Add in the Front button. But the string values won't show, all I can see are the index numbers 1., 2., 3., ect.
I tried putting the id="firsttree" in the <input type="text"> html tag, but the array would disappear when I load it on the web page.
JS
var originalArray = ['spruce', 'pine', 'cedar', 'maple', 'oak', 'birch', 'aspen'];
// Iterate array and display
originalArray.forEach(element => {
// Creates an Element Node with the specified name.
let listItem = document.createElement("li");
// creates a Text Node with the specified text.
let itemDescription = document.createTextNode(element);
// append: Add Item or Element
listItem.appendChild(itemDescription);
/*document.getElementById("firsttree").innerHTML = originalArray;*/
// Returns the element that has the ID attribute with the specified value and adds a node to the end of the list of children of the specified parent node
document.getElementById("firsttree").appendChild(listItem);
});
/**
* Add Items to list
*/
function addItem() {
// Unshift: Add item to beginning of list
originalArray.unshift(document.getElementById('firsttree').value);
// Making the text box empty and re-display
document.getElementById('firsttree').value = " ";
disp(); // displaying the array elements
}
/**
* Render array
*/
function disp() {
var str=" ";
str = originalArray.length + '<br> '; // break the lines to form list.
// Increment the list by 1, i++ if i is less than length
for (i=1; i < originalArray.length; i++) // Initial parameter is 1.
{
// Adding each element with key number to display string
str += i + ". "+ originalArray[i] + "<br> ";
}
// Display the elements of the array
document.getElementById('firsttree').innerHTML=str;
}
HMTL
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="activity3.css">
<!-- ol: Ordered numbered list-->
<!--<script>
/*var trees = ['spruce', 'pine', 'cedar', 'maple', 'oak', 'birch', 'aspen'];*/AbortSignal
/*document.getElementById("oringinalTree").innerHTML = trees;*/
</script>-->
</head>
<body>
<h1>Array Methods</h1>
<br>
<label>
Enter new array element here
</label>
<input type="text">
<button type="button" value="Add" onclick="addItem()" >
Add in the Front
</button>
<button type="text">
Add at the End
</button>
<button type="text">
Add in the Middle
</button>
<button type="text">
Sort
</button>
<button type="text">
Remove Duplicates
</button>
<br>
</form>
<h2>List of Trees</h2>
<h3>Tree Display:</h3>
<!-- Must create div to place list under Header-->
<div class="originalArray">
<ol id="firsttree"></ol>
<!--<link rel="stylesheet" type="text/css" href="path/to/your.css" />-->
<script src="gla3.js"></script>
</div>
<h4>Sorted Tree Display:</h4>
</body>
</html>
css
h3 {
position: absolute;
left: 70px;
top: 200px;
}
h4 {
position: absolute;
left: 300px;
top: 200px;
}
.originalArray {
position: absolute;
top: 250px;
left: 50px;
}
I need to add the string from input to the array and then be displayed, but instead I start off with undefined being added to array and the rest are all blank. Plus I don't want the number of increments (12) to be seen either.

1: Add an id to your input element:
<input type="text" id="new_element">
2: Replace firsttree with new_element in this line:
originalArray.unshift(document.getElementById('new_element').value); // adding element to array
3: Start your loop with i=0 in this line:
for (let i=0; i < originalArray.length; i++)
4: Remove this line if you don't want the number of item in your array to be displayed (the 12 from your screenshot):
str = originalArray.length + '<br> ';
Nowadays, one of the most important thing when learning a new programming language certainly is to fully understand whatever code you get from stack overflow, so don't hesitate if you want me to explain any of those steps.
Here is a example with the other functions added:
var originalArray = ['spruce', 'pine', 'cedar', 'maple', 'oak', 'birch', 'aspen'];
// why not simply use your disp() function
// to display the array at first ?
disp();
// functions to add items
function addItemFront() {
originalArray.unshift(document.getElementById('new_element').value);
document.getElementById('firsttree').value = " ";
disp(); // displaying the array elements
}
function addItemEnd() {
originalArray.push(document.getElementById('new_element').value);
document.getElementById('firsttree').value = " ";
disp();
}
function addItemMiddle() {
originalArray.splice(Math.round(originalArray.length/2), 0, document.getElementById('new_element').value);
document.getElementById('firsttree').value = " ";
disp();
}
// function to remove duplicate
function removeDuplicate() {
originalArray = array_unique(originalArray);
document.getElementById('firsttree').value = " "; // Making the text box blank
disp(); // displaying the array elements
}
// more info on this one at: https://stackoverflow.com/questions/25530168/is-there-a-function-like-array-unique-in-jquery
function array_unique(array){
return array.filter(function(el, index, arr) {
return index == arr.indexOf(el);
});
}
// function to display the array
function disp() {
var str=" ";
for (i=0; i < originalArray.length; i++){
str += i + ". "+ originalArray[i] + "<br> ";
}
document.getElementById('firsttree').innerHTML=str;
}
// function to display the sorted array
function dispSorted() {
var str=" ";
var sortedArray = originalArray.sort();
for (i=0; i < sortedArray.length; i++){
str += i + ". "+ sortedArray[i] + "<br> ";
}
document.getElementById('sortedtree').innerHTML=str;
}
.originalArray {
position: absolute;
top: 250px;
left: 50px;
}
.sortedArray {
position: absolute;
top: 250px;
left: 450px;
}
<h1>Array Methods</h1>
<br>
<div class="field">Enter new array element here</div>
<input type="text" id="new_element">
<button type="button" onclick="addItemFront();">Add in the Front</button>
<button type="button" onclick="addItemEnd();">Add at the End</button>
<button type="button" onclick="addItemMiddle();">Add in the Middle</button>
<button type="button" onclick="dispSorted();">Sort</button>
<button type="button" onclick="removeDuplicate();">Remove Duplicates</button>
<br>
<h2>List of Trees</h2>
<div class="originalArray">
<h3>Tree Display:</h3>
<ol id="firsttree"></ol>
</div>
<div class="sortedArray">
<h4>Sorted Tree Display:</h4>
<ol id="sortedtree"></ol>
</div>

For the addItem() Just like #françois-huppé mentioned, you need to add an id to the input text.
function addItem() {
originalArray.unshift(document.getElementById('new_element').value);
document.getElementById('new_element').value = "";
disp();
}
function disp() {
let str = "";
for (let i = 0; i < originalArray.length; i++) {
str += `<li>${originalArray[i]}</li>`;
}
document.getElementById('firsttree').innerHTML = str;
}
On the disp() function, there are two things to note.
Since you are appending each value to an Ordered List <ol>, you don't need a line break <br> because <li> has a display-block property by default which will display each item on a new line.
You also do not need to number the items str += i + ". "+ originalArray[i] the ordered-list will number it.
You can check the working solution here https://codepen.io/sirwhite/pen/mddKxqr

Related

Split multiple class with same name using loop

I have a multiple tag in my webpage with the same class called price. Each tag is of that form
<p class="price">Price: 45$</p>
<p class="price">Price: 32$</p>
What I need at the end is to separate the price text in a span and the price in another so that it will be like that
<p class="price"><span class='h1'>Price:</span> <span class="h2">45$</span></p>
This is what I do until now but problem is that the span is not a tag but is insert as a simple string
let price = $(".price");
for (let i = 0; i < price.length; i++) {
let priceTitle = price[i].innerText.split(":")[0];
let priceToPay = price[i].innerText.split(":")[1];
price[i].innerText = ''; //Delete content of price
$(".price")[i].append("<span class='h1'>"+ priceTitle+"</span> <span class='h2'>"+ priceToPay +"</span>");
}
}
Can you help me fix this issue and perhaps optimize the code I already do.
You've just a few syntax errors e.g. you've set priceToPay then used price_toPay in your final line of code. Also jQuery.append() method is setting your content as textContent and not HTML but just use innerHTML instead. I've added a button for you to click so you can see the before and after effects. See below
window.onload = () => {
document.getElementById('mybutton').addEventListener('click', doFormat);
}
function doFormat() {
let price = $(".price");
for (let i = 0; i < price.length; i++) {
const priceTextContentArray = price[i].innerText.split(":");
let priceTitle = priceTextContentArray[0];
let priceToPay = priceTextContentArray[1];
price[i].innerHTML =
"<span class='h1'>" +
priceTitle +
"</span> <span class='h2'>" +
priceToPay +
"</span>";
}
}
.h1 {
background-color: skyblue;
}
.h2 {
background-color: coral;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js" integrity="sha512-aVKKRRi/Q/YV+4mjoKBsE4x3H+BkegoM/em46NNlCqNTmUYADjBbeNefNxYV7giUp0VxICtqdrbqU7iVaeZNXA==" crossorigin="anonymous" referrerpolicy="no-referrer" defer></script>
<button id='mybutton'>Format</button><br>
<p class="price">Price: 45$</p>
<p class="price">Price: 32$</p>
If you want to do it "the jQuery way", to build elements from strings you must use the $ constructor:
replace:
price[i].innerText = ''; //Delete content of price
$(".price")[i].append("<span class='h1'>"+ priceTitle+"</span> <span class='h2'>"+ priceToPay +"</span>");
by:
$(price[i]).html('').append( $("<span class='h1'>"+ priceTitle +"</span> <span class='h2'>"+ priceToPay +"</span>") );
As you see in jQuery you can also chain the calls, and use the .html() or .text() dedicated functions. html is more suitable here as you want to delete all inside your element, not just the text part
Notice that I also corrected your $(".price")[i] to $(price[i]), it is safer to use the var you loop on instead of doing a new jQuery selection and assume it will have the same index as in your loop

How to search page for words and highlight them (JQuery)

I currently have an array of user inputted words and respective highlight colors stored in objects (below is the function that constructs the array upon user button click and input):
//DECLERATIONS////
var placementId = 0;
var searchList = [];
///FUNCTION THAT ADDS A NEW WORD TO SEARCHLIST////////
function addWord(userWord, userColor){ //append new word to find and highlight
var wordAndColorPair = {
word: userWord,
color: userColor,
id: placementId
}
searchList.push(wordAndColorPair);
}
///////BELOW IS THE EVENT THAT ACTUALLY CONSTRUCTS THE ARRAY//////////
$('.color-element').click(function(){ //adding new word-color pairs
var userInput = $('#input-word').val();
if(userInput !== ''){ //only if user enteres text:
var newWord = document.createElement("span"); //create a new search word tile
newWord.classList.add('search-word'); //add the class search-word to it
newWord.textContent = userInput; //make its text value equal to the input
var colorId = $(this).attr('id'); //set its bacckground color to a copy of the button clicked
$(newWord).css("background-color", colorId);
$(newWord).attr('id', placementId); //set this new elements unique ID for delection purposes
$('.display-array').append(newWord); //append the child to the DOM
addWord(userInput, colorId, placementId); //add the word to the search list - increment placementId for future words
placementId ++;
$('#input-word').val(''); //reset the input field
}
else{
return;
}
});
What I am having trouble with is being able to search the whole page and actually highlight the words seen in the array. What I have so far is:
$('.search').click(function(){ //when the search button is clicked
var i;
for(i =0; i< searchList.length; i++){//for each word user inputted:
$("*").contents().each(function() {
var word = searchList[i].word;
var regex = new RegExp('(\\b'+word+'\\b)', 'gi');
if(this.nodeType == 3){ //if text
$(this).html(text.replace(regex, " <span style = 'background-color: " + searchList[i].color + " ;'> " + searchList[i].word + "</span>"));
}
});
}
});
This, however, does not seem to be working, any assistance is much appreciated!
HTML for DOM reference:
<html lang="en">
<head>
<link href="https://fonts.googleapis.com/css?family=Changa:700|Roboto+Condensed:700" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto+Slab" rel="stylesheet">
<script src="http://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script type = "text/javascript" src="popup.js"></script>
<meta charset="utf-8">
<title>Word Finder</title>
<link rel="stylesheet" href="style.css" media="screen">
<meta name="description" content="Word Finder Chrome Extension">
<meta name="author" content="Aalok Borkar">
</head>
<body>
<p>
this is a test of the funcitonality TEXT text text text hello
</p>
<div class = "input">
<div class = "word">
Word <input type = "text" id = 'input-word' placeholder= "Jim Halpert"></input>
</div>
<div class = "color-palette">
<!-- on click: clear text input, add color, append search array / display array -->
<button class = "color-element" id = "red"></button>
<button class = "color-element" id = "orange"></button>
<button class = "color-element" id = "yellow"></button>
<button class = "color-element" id = "green"></button>
<button class = "color-element" id = "blue"></button>
<button class = "color-element" id = "violet"></button>
<button class = "color-element" id = "pink"></button>
</div>
</div>
<div class = "display">
<p> Words to Search</p>
<div class = "display-array">
</div>
</div>
<button class = "search">Search</button>
</body>
</html>
It need to be done that way:
$(this).parent().html($(this).parent().html().replace($(this).text(),$(this).text().replace(regex, " <span style = 'background-color: " + searchList[i].color + " ;'>" + searchList[i].word + "</span> ")));
This is because when you change the innerHTML directly you will mess the dom structure and lose the html format, when you change the text solely you would have a a sanitized DOM inside quotes, so it should be solved one way by modifying the text part inside the inner html.
see it here
I added a class to your <p> element, but you probably don't have to do that. I just did it for ease of access on my part. The biggest thing, if I understood your question right, was your search function. IMO, you need to look at each word and compare it to the search array. Find the word that matches and wrap it in something that you can apply a style to. In my case, I chose a <span> tag. Fiddle below code.
// HTML Modification
<p class="searchable">
this is a test of the functionality TEXT text text text hello
</p>
$('.search').click(function() { //when the search button is clicked
var original = $('.searchable').html().trim();
var searchable = original.split(" ");
for (var i = 0; i < searchList.length; i++) { //for each word user
inputted:
for (var s = 0; s < searchable.length; s++) {
if (searchable[s] == searchList[i].word) {
searchable[s] = "<span style='background:" + searchList[i].color +
";'>" + searchList[i].word + "</span>";
}
}
}
rewrite(searchable); //SEE BELOW
});
// This iterates over the searchable array
function rewrite(searchable) {
var highlighted = "";
for (var i = 0; i < searchable.length; i++) {
highlighted += searchable[i] + " ";
}
$('.searchable').html(highlighted.trim());
}
https://jsfiddle.net/5v3aqrzd/

Simple javascript: arrays, and form information gathering #2

I don't know javascript much at all, I just like making lists for myself. I am currently trying to create a html page that I can keep track of characters from my favorite game, but I have run across a couple of problems I don't know how to solve.
<form name="inputNightlife" id="inputNightlife">
<h2>Nightlife</h2>
<label for="traits"><b>Traits:</b></label><br>
<select multiple="true" name="traits" id="traits">
<option value="Cologne">Cologne</option>
<option value="Stink">Stink</option>
<option value="Fatness">Fatness</option>
<option value="Fitness">Fitness</option>
</select>
<label for="turnOns"><b>Turn Ons:</b></label><br>
<select multiple="true" name="turnOns" id="turnOns">
<option value="Blonde Hair">Blonde Hair</option>
<option value="Red Hair">Red Hair</option>
<option value="Brown Hair">Brown Hair</option>
<option value="Black Hair">Black Hair</option>
</select>
<p>Select all that apply.</p>
<nav id="box8" class="hide"><table id="menu3"><tr><td rowspan="2" id="soft">
<textarea name="source8" onclick="this.focus();this.select()" cols="40" rows="3" id="result">
</textarea></td><td>
<input type="button" value="Get Code!" onclick="javascript:generateNightlife();"></td>
<td rowspan="2" id="softA">
<img src="./forSCV/icons/nightlife.png" alt="Nightlife" title="Nightlife" id="arrow" onclick="toggle('box8');">
</td></tr><tr><td>
<input type="button" value="Test Code" onclick="javascript:displayNightlife(this.form);">
</td></tr></table></nav></form>
When I click the button, the document.results.endresults.value appears in the text area. I can then copy the results, and save them as html. This is intended to be a page generator (the best I can come up with).
I am not sure how to make traits and turnOns automatically create an array (with spaces) of the chosen options that will then print in the document.result.endresult.value. I did find several different ways to create an array from the forms, but not how to then get it to go into the document.result.endresult.value.
One way Google. And another way Google
Adding...
Ok, I reworked my html to include names and id's, and I found a little better page generator, so I was trying to get that to work. Now I have tried this.
function byId(idStr){return document.getElementById(idStr);}
function getFormValues() {
var traitsSelectElem = byId('traits');
var turnOnsSelectElem = byId('turnOns');
var chosenTraits = getSelectedOptions(traitsSelectElem);
var chosenTurnOns = getSelectedOptions(turnOnsSelectElem);
var i, n, outputStr;
n = chosenTraits.length;
outputStr = '';
for (i = 0; i < n; i ++)
{
if (outputStr != ".")
outputStr += ", ";
outputStr += chosenTraits[i].value;
}
byId('traitsOutput').innerText = outputStr;
n = chosenTurnOns.length;
outputStr = '';
for (i = 0; i < n; i++)
{
if (outputStr != '.')
outputStr += ', ';
outputStr += chosenTurnOns[i].value;
}
byId('turnOnsOutput').innerText = outputStr;
}
function getSelectedOptions(selectElem) {
var i, nOptions = selectElem.options.length;
var result = [];
for (i = 0; i < nOptions; i++)
{
if (selectElem.options[i].selected)
{
result.push(
{
value: selectElem.option[i].value
}
);
}
}
return result;
}
function generateNightlife() {
//nightlife
var traits = getFormValues();
var turnOns = getFormValues();
turnOff = document.inputNightlife.turnOff.value;
perfumeDuration = document.inputNightlife.perfumeDuration.value;
lovePotion = document.inputNightlife.lovePotion.value;
outputNightlife = "<a name='nightlife'></a>\n<div id='easy'>\n<h2>Nightlife</h2>\n
<table class='ntlf'><tr><th>Traits:</th><td class='white'>"+traits+"
</td></tr><tr><th>Turn Ons:</th><td class='white'>"+turnOnsOutput+"</td></tr><tr><th>
Turn Offs:</th><td class='white'>"+turnOff+"</td></tr></table>\n<p class='up2'>Perfume
Duration: <span class='colorme'>"+perfumeDuration+"</span></p>\n<p>Love Potion Duration:
<span class='colorme'>"+lovePotion+"</span></p>\n</div>\n"
document.inputNightlife.source8.value = outputNightlife;
return outputNightlife;
}
When I test it with chrome it says it cannot set property of .innerText of null which I think is because I don't want it to go to a div. I would like the value returned back to function generateNightlife so that it can be added to the outputNightlife. I don't know how to do that, and I need some help.
Here's a fully worked example that will pull multiple selections from a select element, before going on to construct an array with them, and finally printing them to screen.
Either of the two tutes you linked to are okay - it's always hard to know what will be obvious, what will need explaining and what will rely on background information that may/may not have already been covered.
I've used a few different tricks here and there are many that are more sophisticated I've elected to eschew. I hope the comments make the operation clear, though would be happy to add clarification as needed. :)
Here's a runnable snippet:
function byId(idStr){return document.getElementById(idStr);}
function getFormValues()
{
// 1. get a reference to each of the select elemenets we wish to process
var mainMealSelectElem = byId('mainSelect');
var dessertSelectElem = byId('dessertSelect');
// 2. get an array of all of the selected options in each of our select elements
var chosenMains = getSelectedOptions(mainMealSelectElem);
var chosenSweets = getSelectedOptions(dessertSelectElem);
var i, n, outputStr;
n = chosenMains.length;
outputStr = '';
for (i=0; i<n; i++)
{
// only add a comma before an element if at least one element already exists
// this is how we do it when writing a list manually.
if (outputStr != '')
outputStr += ", ";
// grab the two values from the array we constructed using the getSelectedOptions function.
// we said that each array element would have 2 fields, and named them "value" and "textLabel" - both entirely arbitrary name.
// whatever we named them in the below function is what we need to use to access them here.
outputStr += chosenMains[i].textLabel + " (" + chosenMains[i].value + ")";
}
// set the text content of the target span with the array of chosen stuff.
byId('mainsOutput').innerText = outputStr;
n = chosenSweets.length;
outputStr = '';
for (i=0; i<n; i++)
{
if (outputStr != '')
outputStr += ", ";
outputStr += chosenSweets[i].textLabel + " (" + chosenSweets[i].value + ")";
}
byId('dessertsOutput').innerText = outputStr;
}
// returns an array that consists of <value, text-label> pairs - 1 element for each selected option.
function getSelectedOptions(selectElem)
{
// aloop counter and the total number of iterations required
var i, nOptions = selectElem.options.length;
// the empty result array
var result = [];
// loop through all the options this select element has
for (i=0; i<nOptions; i++)
{
// if the current option is selected, we'll need to extract it's info and add it to the output array
if (selectElem.options[i].selected)
{
result.push(
{
value: selectElem.options[i].value,
textLabel: selectElem.options[i].label
}
);
}
}
return result;
}
div
{
display: inline-block;
}
.centered
{
text-align: center;
}
<div class='centered'>
<form>
<h2>Select the ones you like</h2>
<select id='mainSelect' multiple>
<option value='spag'>Spaghetti</option>
<option value='satay'>Peanut satay</option>
<option value='schnitz'>Chicken Schnitzel</option>
</select>
<select id='dessertSelect' multiple>
<option value='1'>Ice-cream</option>
<option value='2'>Fruit salad</option>
<option value='3'>Custard</option>
</select>
</form>
<br>
<button onclick='getFormValues()'>Get chosen values</button>
<hr>
</div>
<br>
<div>
Selected main-meals: <span id='mainsOutput'></span><br>
Selected desserts: <span id='dessertsOutput'></span><br>
</div>
And here's the full (copy/pastable) source:
<!doctype html>
<html>
<head>
<script>
function byId(idStr){return document.getElementById(idStr);}
function getFormValues()
{
// 1. get a reference to each of the select elemenets we wish to process
var mainMealSelectElem = byId('mainSelect');
var dessertSelectElem = byId('dessertSelect');
// 2. get an array of all of the selected options in each of our select elements
var chosenMains = getSelectedOptions(mainMealSelectElem);
var chosenSweets = getSelectedOptions(dessertSelectElem);
var i, n, outputStr;
n = chosenMains.length;
outputStr = '';
for (i=0; i<n; i++)
{
// only add a comma before an element if at least one element already exists
// this is how we do it when writing a list manually.
if (outputStr != '')
outputStr += ", ";
// grab the two values from the array we constructed using the getSelectedOptions function.
// we said that each array element would have 2 fields, and named them "value" and "textLabel" - both entirely arbitrary name.
// whatever we named them in the below function is what we need to use to access them here.
outputStr += chosenMains[i].textLabel + " (" + chosenMains[i].value + ")";
}
// set the text content of the target span with the array of chosen stuff.
byId('mainsOutput').innerText = outputStr;
n = chosenSweets.length;
outputStr = '';
for (i=0; i<n; i++)
{
if (outputStr != '')
outputStr += ", ";
outputStr += chosenSweets[i].textLabel + " (" + chosenSweets[i].value + ")";
}
byId('dessertsOutput').innerText = outputStr;
}
// returns an array that consists of <value, text-label> pairs - 1 element for each selected option.
function getSelectedOptions(selectElem)
{
// aloop counter and the total number of iterations required
var i, nOptions = selectElem.options.length;
// the empty result array
var result = [];
// loop through all the options this select element has
for (i=0; i<nOptions; i++)
{
// if the current option is selected, we'll need to extract it's info and add it to the output array
if (selectElem.options[i].selected)
{
result.push(
{
value: selectElem.options[i].value,
textLabel: selectElem.options[i].label
}
);
}
}
return result;
}
</script>
<style>
div
{
display: inline-block;
}
.centered
{
text-align: center;
}
</style>
</head>
<body>
<div class='centered'>
<form>
<h2>Select the ones you like</h2>
<select id='mainSelect' multiple>
<option value='spag'>Spaghetti</option>
<option value='satay'>Peanut satay</option>
<option value='schnitz'>Chicken Schnitzel</option>
</select>
<select id='dessertSelect' multiple>
<option value='1'>Ice-cream</option>
<option value='2'>Fruit salad</option>
<option value='3'>Custard</option>
</select>
</form>
<br>
<button onclick='getFormValues()'>Get chosen values</button>
<hr>
</div>
<br>
<div>
Selected main-meals: <span id='mainsOutput'></span><br>
Selected desserts: <span id='dessertsOutput'></span><br>
</div>
</body>
</html>

Store values from dynamically generated text boxes into array

I'm creating a Time table generating website as a part of my project and I am stuck at one point.
Using for loop, I am generating user selected text boxes for subjects and faculties. Now the problem is that I cannot get the values of those dynamically generated text boxes. I want to get the values and store it into array so that I can then later on store it to database
If I am using localstorage, then it sometimes shows NaN or undefined. Please help me out.
Following is my Jquery code
$.fn.CreateDynamicTextBoxes = function()
{
$('#DynamicTextBoxContainer, #DynamicTextBoxContainer2').css('display','block');
InputtedValue = $('#SemesterSubjectsSelection').val();
SubjectsNames = [];
for (i = 0; i < InputtedValue; i++)
{
TextBoxContainer1 = $('#DynamicTextBoxContainer');
TextBoxContainer2 = $('#DynamicTextBoxContainer2');
$('<input type="text" class="InputBoxes" id="SubjectTextBoxes'+i+'" placeholder="Subject '+i+' Name" style="margin:5px;" value=""><br>').appendTo(TextBoxContainer1);
$('<input type="text" class="InputBoxes" id="FacultyTextBoxes'+i+'" placeholder="Subject '+i+' Faculty Name" style="margin:5px;" value=""><br>').appendTo(TextBoxContainer2);
SubjectsNames['SubjectTextBoxes'+i];
}
$('#DynamicTextBoxContainer, #UnusedContainer, #DynamicTextBoxContainer2').css('border-top','1px solid #DDD');
}
$.fn.CreateTimeTable = function()
{
for (x = 0; x < i; x++)
{
localStorage.setItem("Main"+x, +SubjectsNames[i]);
}
}
I am also posting screenshot for better understanding
I understand you create 2 text boxes for each subject, one for subject, and second one for faculty. And you want it as a jQuery plugin.
First of all, I think you should create single plugin instead of two, and expose what you need from the plugin.
You should avoid global variables, right now you have InputtedValue, i, SubjectsNames, etc. declared as a global variables, and I believe you should not do that, but keep these variables inside you plugin and expose only what you really need.
You declare your SubjectNames, but later in first for loop you try to access its properties, and actually do nothing with this. In second for loop you try to access it as an array, but it's empty, as you did not assign any values in it.
Take a look at the snippet I created. I do not play much with jQuery, and especially with custom plugins, so the code is not perfect and can be optimized, but I believe it shows the idea. I pass some selectors as in configuration object to make it more reusable. I added 2 buttons to make it more "playable", but you can change it as you prefer. Prepare button creates your dynamic text boxes, and button Generate takes their values and "print" them in result div. generate method is exposed from the plugin to take the values outside the plugin, so you can do it whatever you want with them (e.g. store them in local storage).
$(function() {
$.fn.timeTables = function(config) {
// prepare variables with jQuery objects, based on selectors provided in config object
var numberOfSubjectsTextBox = $(config.numberOfSubjects);
var subjectsDiv = $(config.subjects);
var facultiesDiv = $(config.faculties);
var prepareButton = $(config.prepareButton);
var numberOfSubjects = 0;
prepareButton.click(function() {
// read number of subjects from the textbox - some validation should be added here
numberOfSubjects = +numberOfSubjectsTextBox.val();
// clear subjects and faculties div from any text boxes there
subjectsDiv.empty();
facultiesDiv.empty();
// create new text boxes for each subject and append them to proper div
// TODO: these inputs could be stored in arrays and used later
for (var i = 0; i < numberOfSubjects; i++) {
$('<input type="text" placeholder="Subject ' + i + '" />').appendTo(subjectsDiv);
$('<input type="text" placeholder="Faculty ' + i + '" />').appendTo(facultiesDiv);
}
});
function generate() {
// prepare result array
var result = [];
// get all text boxes from subjects and faculties divs
var subjectTextBoxes = subjectsDiv.find('input');
var facultiesTextBoxes = facultiesDiv.find('input');
// read subject and faculty for each subject - numberOfSubjects variable stores proper value
for (var i = 0; i < numberOfSubjects; i++) {
result.push({
subject: $(subjectTextBoxes[i]).val(),
faculty: $(facultiesTextBoxes[i]).val()
});
}
return result;
}
// expose generate function outside the plugin
return {
generate: generate
};
};
var tt = $('#container').timeTables({
numberOfSubjects: '#numberOfSubjects',
subjects: '#subjects',
faculties: '#faculties',
prepareButton: '#prepare'
});
$('#generate').click(function() {
// generate result and 'print' it to result div
var times = tt.generate();
var result = $('#result');
result.empty();
for (var i = 0; i < times.length; i++) {
$('<div>' + times[i].subject + ': ' + times[i].faculty + '</div>').appendTo(result);
}
});
});
#content div {
float: left;
}
#content div input {
display: block;
}
#footer {
clear: both;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="container">
<div id="header">
<input type="text" id="numberOfSubjects" placeholder="Number of subjects" />
<button id="prepare">
Prepare
</button>
</div>
<div id="content">
<div id="subjects">
</div>
<div id="faculties">
</div>
</div>
</div>
<div id="footer">
<button id="generate">Generate</button>
<div id="result">
</div>
</div>

A good JavaScript to add/remove items from/to array?

folks! Today I created this script that has the following functionality:
add new items to array
list all items from the array
remove an item from the array
There are two functions:
addToFood() - adds the value of input to the array and updates
innerHTML of div
removeRecord(i) - remove a record from the array and updates
innerHTML of div
The code includes 3 for loops and you can see it at - http://jsfiddle.net/menian/3b4qp/1/
My Master told me that those 3 for loops make the solution way to heavy. Is there a better way to do the same thing? Is it better to decrease the loops and try to use splice? Thanks in advance.
HTML
<!-- we add to our foodList from the value of the following input -->
<input type="text" value="food" id="addFood" />
<!-- we call addToFood(); through the following button -->
<input type="submit" value="Add more to food" onClick="addToFood();">
<!-- The list of food is displayed in the following div -->
<div id="foods"></div>
JavaScript
var foodList = [];
function addToFood () {
var addFood = document.getElementById('addFood').value;
foodList.push(addFood);
for (i = 0; i < foodList.length; i++) {
var newFood = "<a href='#' onClick='removeRecord(" + i + ");'>X</a> " + foodList[i] + " <br>";
};
document.getElementById('foods').innerHTML += newFood;
}
function removeRecord (i) {
// define variable j with equal to the number we got from removeRecord
var j = i;
// define and create a new temporary array
var tempList = [];
// empty newFood
// at the end of the function we "refill" it with the new content
var newFood = "";
for (var i = 0; i < foodList.length; i++) {
if(i != j) {
// we add all records except the one == to j to the new array
// the record eual to j is the one we've clicked on X to remove
tempList.push(foodList[i]);
}
};
// make redefine foodList by making it equal to the tempList array
// it should be smaller with one record
foodList = tempList;
// re-display the records from foodList the same way we did it in addToFood()
for (var i = 0; i < foodList.length; i++) {
newFood += "<a href='#' onClick='removeRecord(" + i + ");'>X</a> " + foodList[i] + " <br>";
};
document.getElementById('foods').innerHTML = newFood;
}
You should use array.splice(position,nbItems)
function removeRecord (i) {
foodList.splice(i, 1); // remove element at position i
var newFood = "";
for (var i = 0; i < foodList.length; i++) {
newFood += "<a href='#' onClick='removeRecord(" + i + ");'>X</a> "
+ foodList[i] + " <br>";
};
document.getElementById('foods').innerHTML = newFood;
}
http://jsfiddle.net/3b4qp/5/
Now using JQuery:
$(function(){
$(document).on('click','input[type=submit]',function(){
$('#foods')
.append('<div>X '
+ $('#addFood').val() + '</div>');
});
$(document).on('click','.item',function(){
$(this).parent().remove();
});
});
http://jsfiddle.net/jfWa3/
Your problem isn't the arrays, your problem is this code:
node.innerHTML += newFood;
This code is very, very, very slow. It will traverse all exising DOM nodes, create strings from them, join those strings into one long string, append a new string, parse the result to a new tree of DOM nodes.
I suggest to use a framework like jQuery which has methods to append HTML fragments to existing DOM nodes:
var parent = $('#foods');
...
for (var i = 0; i < foodList.length; i++) {
parent.append( "<a href='#' onClick='removeReco..." );
That will parse the HTML fragments only once.
If you really must do it manually, then collect all the HTML in a local string variable (as suggested by JohnJohnGa in his answer) and then assign innerHTML once.
Here's some tips to, at least, make your code more portable (dunno if it will be better performance wise, but should be, since DOM Manipulation is less expensive)
Tips
First separate your event handle from the HTML
Pass the "new food" as a function paramater
Tie the array elements to the DOM using the ID
Instead of rerendering everything when something changes (using innerHTML in the list), just change the relevant bit
Benefits:
You actually only loop once (when removing elements from the array).
You don't re-render the list everytime something changes, just the element clicked
Added bonus: It's more portable.
Should be faster
Example code:
FIDDLE
HTML
<div id="eventBinder">
<!-- we add to our foodList from the value of the following input -->
<input id="addFood" type="text" value="food" />
<!-- we call addToFood(); through the following button -->
<button id="addFoodBtn" value="Add more to food">Add Food</button>
<!-- The list of food is displayed in the following div
-->
<div id="foods"></div>
</div>
JS
// FoodList Class
var FoodList = function (selectorID) {
return {
foodArray: [],
listEl: document.getElementById(selectorID),
idCnt: 0,
add: function (newFood) {
var id = 'myfood-' + this.idCnt;
this.foodArray.push({
id: id,
food: newFood
});
var foodDom = document.createElement('div'),
foodText = document.createTextNode(newFood);
foodDom.setAttribute('id', id);
foodDom.setAttribute('class', 'aFood');
foodDom.appendChild(foodText);
this.listEl.appendChild(foodDom);
++this.idCnt;
},
remove: function (foodID) {
for (var f in this.foodArray) {
if (this.foodArray[f].id === foodID) {
delete this.foodArray[f];
var delFood = document.getElementById(foodID);
this.listEl.removeChild(delFood);
}
}
}
};
};
//Actual app
window.myFoodList = new FoodList('foods');
document.getElementById('eventBinder').addEventListener('click', function (e) {
if (e.target.id === 'addFoodBtn') {
var food = document.getElementById('addFood').value;
window.myFoodList.add(food);
} else if (e.target.className === 'aFood') {
window.myFoodList.remove(e.target.id);
}
}, false);
Here is another sugestion:
function remove(arr, index) {
if (index >= arr.lenght) { return undefined; }
if (index == 0) {
arr.shift();
return arr;
}
if (index == arr.length - 1) {
arr.pop();
return arr;
}
var newarray = arr.splice(0, index);
return newarray.concat(arr.splice(1,arr.length))
}

Categories

Resources