Store values from dynamically generated text boxes into array - javascript

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>

Related

LocalStorage and adding li to list

I'm trying to make a small script that allows for a little notes section. This section would have an input box that allows for adding elements to the list; which will be saved in localStorage so they are not lost when I refresh or close the browser. The code I have is as follows (it's all done through JS even the html, but ignore that.)
var notes = [];
var listthings = "<h2 id=\"titlething\">Notes</h2>" +
"<ul id=\"listing\">" +
"</ul>"
"<input type=\"text\" name=\"item\" id=\"textfield\">" +
"<input type=\"submit\" id=\"submitthing\" value=\"Submit\">";
JSON.parse(localStorage.getItem('notes')) || [].forEach( function (note) {
"<li id=\"listitem\">" + notes + "</li>";
})
$('#submitthing').click(function() {
notes.push($('#textfield').val());
});
localStorage.setItem('notes', JSON.stringify(notes));
Also, how would I go about appending the latest added li between the opening and closing tag? Obviously I'd usually do it using jQuery, but this is puzzling me a little. However, only the 'Notes' loads at the top, any ideas?
Your approach is way off the mark. You don't need JSON at all (this just confuses things) and you don't need to manually create HTML.
Also, you can use an array to store the notes, but since localStorage is the storage area, so an array is redundant. Additionally, without using an array, you don't need JSON. The entire problem becomes much easier to solve.
Unfortunately, the following won't run here in this snippet editor, due to security issues, but it would do what you are asking. This fiddle shows it working: https://jsfiddle.net/Lqjwbn1r/14/
// Upon the page being ready:
window.addEventListener("DOMContentLoaded", function(){
// Get a reference to the empty <ul> element on the page
var list = document.getElementById("notes");
// Loop through localStorage
for (var i = 0; i < localStorage.length; i++){
// Make sure that we only read the notes from local storage
if(localStorage.key(i).indexOf("note") !== -1){
// For each item, create a new <li> element
var item = document.createElement("li");
// Populate the <li> with the contents of the current
// localStorage item's value
item.textContent = localStorage.getItem(localStorage.key(i));
// Append the <li> to the page's <ul>
list.appendChild(item);
}
}
// Get references to the button and input
var btn = document.getElementById("btnSave");
var note = document.getElementById("txtNote");
// Store a note count:
var noteCount = 1;
// When the button is clicked...
btn.addEventListener("click", function(){
// Get the value of the input
var noteVal = note.value;
// As long as the value isn't an empty string...
if(noteVal.trim() !== ""){
// Create the note in localStorage using the
// note counter so that each stored item gets
// a unique key
localStorage.setItem("note" + noteCount, noteVal);
// Create a new <li>
var lstItem = document.createElement("li");
// Set the content of the <li>
lstItem.textContent = noteVal;
// Append the <li> to the <ul>
list.appendChild(lstItem);
// Bump up the note counter
noteCount++;
}
});
});
<input type=text id=txtNote><input type=button value=Save id=btnSave>
<ul id=notes></ul>
This is how I would approach it using jquery. but depens how complex this should be. this is just simple demo.
<input type="text" id="note" />
<button id="add">add note</button>
<ul id="notes"></ul>
javascript and jquery
function addNote(){
var data = localStorage.getItem("notes")
var notes = null;
if(data != null)
{
notes = JSON.parse(data);
}
if(notes == null){
notes = [];
}
notes.push($("#note").val());
localStorage.setItem("notes", JSON.stringify(notes));
refreshNotes();
}
function refreshNotes(){
var notesElement =$("#notes");
notesElement.empty();
var notes = JSON.parse(localStorage.getItem("notes"));
for(var i = 0; i< notes.length; i++){
var note = notes[i];
notesElement.append("<li>"+note+"</li>");
}
}
$(function(){
refreshNotes();
$("#add").click(function(){
addNote();
});
})
example:
http://codepen.io/xszaboj/pen/dOXEey?editors=1010

Fast filter in a list of records with JavaScript

I have a list with about 10 000 customers on a web page and need to be able to search within this list for matching input. It works with some delay and I'm looking for the ways how to improve performance. Here is simplified example of HTML and JavaScript I use:
<input id="filter" type="text" />
<input id="search" type="button" value="Search" />
<div id="customers">
<div class='customer-wrapper'>
<div class='customer-info'>
...
</div>
</div>
...
</div>
<script type="text/javascript">
$(document).ready(function() {
$("#search").on("click", function() {
var filter = $("#filter").val().trim().toLowerCase();
FilterCustomers(filter);
});
});
function FilterCustomers(filter) {
if (filter == "") {
$(".customer-wrapper").show();
return;
}
$(".customer-info").each(function() {
if ($(this).html().toLowerCase().indexOf(filter) >= 0) {
$(this).parent().show();
} else {
$(this).parent().hide();
}
});
}
</script>
The problem is that when I click on Search button, there is a quite long delay until I get list with matched results. Are there some better ways to filter list?
1) DOM manipulation is usually slow, especially when you're appending new elements. Put all your html into a variable and append it, that results in one DOM operation and is much faster than do it for each element
function LoadCustomers() {
var count = 10000;
var customerHtml = "";
for (var i = 0; i < count; i++) {
var name = GetRandomName() + " " + GetRandomName();
customerHtml += "<div class='customer-info'>" + name + "</div>";
}
$("#customers").append(customerHtml);
}
2) jQuery.each() is slow, use for loop instead
function FilterCustomers(filter) {
var customers = $('.customer-info').get();
var length = customers.length;
var customer = null;
var i = 0;
var applyFilter = false;
if (filter.length > 0) {
applyFilter = true;
}
for (i; i < length; i++) {
customer = customers[i];
if (applyFilter && customer.innerHTML.toLowerCase().indexOf(filter) < 0) {
$(customer).addClass('hidden');
} else {
$(customer).removeClass('hidden');
}
}
}
Example: http://jsfiddle.net/29ubpjgk/
Thanks to all your answers and comments, I've come at least to solution with satisfied results of performance. I've cleaned up redundant wrappers and made grouped showing/hiding of elements in a list instead of doing separately for each element. Here is how filtering looks now:
function FilterCustomers(filter) {
if (filter == "") {
$(".customer-info").show();
} else {
$(".customer-info").hide();
$(".customer-info").removeClass("visible");
$(".customer-info").each(function() {
if ($(this).html().toLowerCase().indexOf(filter) >= 0) {
$(this).addClass("visible");
}
});
$(".customer-info.visible").show();
}
}
And an test example http://jsfiddle.net/vtds899r/
The problem is that you are iterating the records, and having 10000 it can be very slow, so my suggestion is to change slightly the structure, so you won't have to iterate:
Define all the css features of the list on customer-wrapper
class and make it the parent div of all the list elements.
When your ajax request add an element, create a variable containing the name replacing spaces for underscores, let's call it underscore_name.
Add the name to the list as:
var customerHtml = "<div id='"+underscore_name+'>" + name + "</div>";
Each element of the list will have an unique id that will be "almost" the same as the name, and all the elements of the list will be on the same level under customer-wrapper class.
For the search you can take the user input replace spaces for underscores and put in in a variable, for example searchable_id, and using Jquery:
$('#'+searchable_id).siblings().hide();
siblings will hide the other elements on the same level as searchable_id.
The only problem that it could have is if there is a case of two or more repeated names, because it will try to create two or more divs with the same id.
You can check a simple implementation on http://jsfiddle.net/mqpsppxm/
​

Moving objects between two arrays

I have two lists formed from an array containing objects.
I'm trying to move objects from one list to the other and vice versa.
Controller:
spApp.controller('userCtrl',
function userCtrl($scope,userService,groupService){
//Generate list of all users on the SiteCollection
$scope.users = userService.getUsers();
//array of objects selected through the dom
$scope.selectedAvailableGroups;
$scope.selectedAssignedGroups;
//array of objects the user actually belongs to
$scope.availableGroups;
$scope.assignedGroups;
//Generate all groups on the site
$scope.groups = groupService.getGroups();
//Boolean used to disable add/remove buttons
$scope.selectedUser = false;
//Take the selectedAvailableGroups, add user to those groups
//so push objects to "assignedGroups" array and remove from "avaiableGroups" array
$scope.addUserToGroup = function (){
userService.addUserToGroup($scope.selectedUser, $scope.selectedAvailableGroups, $scope.assignedGroups, $scope.availableGroups)
};
}
);
Service:
spApp.factory('userService', function(){
var addUserToGroup = function (selectedUser, selectedAvailableGroups, assignedGroups, availableGroups) {
var addPromise = [];
var selectLength = selectedAvailableGroups.length;
//Add user to selected groups on server
for (var i = 0; i < selectLength; i++) {
addPromise[i] = $().SPServices({
operation: "AddUserToGroup",
groupName: selectedAvailableGroups[i].name,
userLoginName: selectedUser.domain
});
};
//when all users added, update dom
$.when.apply($,addPromise).done(function (){
for (var i = 0; i < selectLength; i++) {
assignedGroups.push(selectedAvailableGroups[i]);
availableGroups.pop(selectedAvailableGroups[i]);
};
//alert(selectedUser.name + " added to: " + JSON.stringify(selectedAvailableGroups));
});
}
}
Object:
[{
id: 85,
name: Dev,
Description:,
owner: 70,
OwnerIsUser: True
}]
HTML:
<div>
<label for="entityAvailable">Available Groups</label>
<select id="entityAvailable" multiple
ng-model="selectedAvailableGroups"
ng-options="g.name for g in availableGroups | orderBy:'name'">
</select>
</div>
<div id="moveButtons" >
<button type="button" ng-disabled="!selectedUser" ng-click="addUserToGroup()">Add User</button>
<button type="button" ng-disabled="!selectedUser" ng-click="removeUserFromGroup()">Remove</button>
</div>
<div>
<label for="entityAssigned">Assigned Groups</label>
<select id="entityAssigned" multiple
ng-model="selectedAssignedGroups"
ng-options="g.name for g in assignedGroups | orderBy:'name'">
</select>
</div>
Right now, the push into assigned groups works but only updates when I click on something else or in the list, not really dynamically. But the biggest issue is the .pop() which I don't think works as intended.
$.when.apply($,addPromise).done() seems not to be angular api or synchronous. So angular is not aware of your changes. You must wrap your code inside a $scope.$apply call:
$scope.$apply(function(){
for (var i = 0; i < selectLength; i++) {
assignedGroups.push(selectedAvailableGroups[i]);
availableGroups.pop(selectedAvailableGroups[i]);
};
});
If you click on something, a $digest loop will happen and you will see your changes.
Your pop did not work because Array.pop only removes the last element. I guess that is not what you want. If you want to remove a specific element you should use Array.splice(),

how can I call tab key event in javascript

Here is my simple data
John Smith Individual 010987654
I have three textboxes and the above data will automatically insert in the first textbox of my web page.
My problem is
How can I make as soon as data is inserted in the textbox (means when textbox’s onchange event is fired)
First, javascript will find ‘tab’ space in this string
Second, if find ‘tab’ space in the string, javascript will press ‘tab’ key and insert data in the another text box.
Here's a plain old DOM-0 JavaScript solution, just for fun.
document.getElementById('the_form').onchange = function() {
var field = this[0];
var parts = field.value.split('\t');
for (var i = 0; field = this[i]; i++) {
field.value = parts[i] || '';
}
}
http://jsfiddle.net/vKaxP/
I thought you want to split those texts into different textboxes, so I got something like:
$("#a").change(function(){
var s = $(this).val();
if (s.match(/\t+/)) {
var a = s.split(/\t+/);
$('#a').val(a[0]);
$('#b').val(a[1]);
$('#c').val(a[2]);
}
});
if you type a b c into the first input box, press tab or enter, b and c would appear into other textboxes, repectively.
I use \s(space) for test in jsfiddle. You could just change it to \t for tab.
Here is prototype of what you need to do.
HTML:
<div>
<input id="a" />
</div>
<div>
<input id="b" />
</div>
JavaScript:
$('#a').on('change', function () {
var value = $(this).val();
// Test if string has a tab:
if (/\t/.test(value)) {
// Just set the value of the other text box
// And set focus:
// Using jQuery that would be:
$('#b').val(value).focus();
}
});
Working demo: http://jsfiddle.net/tkirda/XmArP/
If I correctly understand the question as "The server puts all the data into one field, tab separated, and I want to split it up into several textfields", then try this:
On load:
var fields = [$("#firstField"), $("#secondField"), $("#thirdField")];
var data = fields[0].val().split(/\t/);
for (var i = 0; i < 3; i++) {
fields[i].val(data[i]);
}

storing user input in array

I need to do the following (I'm a beginner in programming so please excuse me for my ignorance): I have to ask the user for three different pieces of information on three different text boxes on a form. Then the user has a button called "enter"and when he clicks on it the texts he entered on the three fields should be stored on three different arrays, at this stage I also want to see the user's input to check data is actually being stored in the array. I have beem trying unsuccessfully to get the application to store or show the data on just one of the arrays. I have 2 files: film.html and functions.js. Here's the code. Any help will be greatly appreciated!
<html>
<head>
<title>Film info</title>
<script src="jQuery.js" type="text/javascript"></script>
<script src="functions.js" type="text/javascript"></script>
</head>
<body>
<div id="form">
<h1><b>Please enter data</b></h1>
<hr size="3"/>
<br>
<label for="title">Title</label> <input id="title" type="text" >
<br>
<label for="name">Actor</label><input id="name" type="text">
<br>
<label for="tickets">tickets</label><input id="tickets" type="text">
<br>
<br>
<input type="button" value="Save" onclick="insert(this.form.title.value)">
<input type="button" value="Show data" onclick="show()"> <br>
<h2><b>Data:</b></h2>
<hr>
</div>
<div id= "display">
</div>
</body>
</html>
var title=new Array();
var name=new Array();
var tickets=new Array();
function insert(val){
title[title.length]=val;
}
function show() {
var string="<b>All Elements of the Array :</b><br>";
for(i = 0; i < title.length; i++) {
string =string+title[i]+"<br>";
}
if(title.length > 0)
document.getElementById('myDiv').innerHTML = string;
}
You're not actually going out after the values. You would need to gather them like this:
var title = document.getElementById("title").value;
var name = document.getElementById("name").value;
var tickets = document.getElementById("tickets").value;
You could put all of these in one array:
var myArray = [ title, name, tickets ];
Or many arrays:
var titleArr = [ title ];
var nameArr = [ name ];
var ticketsArr = [ tickets ];
Or, if the arrays already exist, you can use their .push() method to push new values onto it:
var titleArr = [];
function addTitle ( title ) {
titleArr.push( title );
console.log( "Titles: " + titleArr.join(", ") );
}
Your save button doesn't work because you refer to this.form, however you don't have a form on the page. In order for this to work you would need to have <form> tags wrapping your fields:
I've made several corrections, and placed the changes on jsbin: http://jsbin.com/ufanep/2/edit
The new form follows:
<form>
<h1>Please enter data</h1>
<input id="title" type="text" />
<input id="name" type="text" />
<input id="tickets" type="text" />
<input type="button" value="Save" onclick="insert()" />
<input type="button" value="Show data" onclick="show()" />
</form>
<div id="display"></div>
There is still some room for improvement, such as removing the onclick attributes (those bindings should be done via JavaScript, but that's beyond the scope of this question).
I've also made some changes to your JavaScript. I start by creating three empty arrays:
var titles = [];
var names = [];
var tickets = [];
Now that we have these, we'll need references to our input fields.
var titleInput = document.getElementById("title");
var nameInput = document.getElementById("name");
var ticketInput = document.getElementById("tickets");
I'm also getting a reference to our message display box.
var messageBox = document.getElementById("display");
The insert() function uses the references to each input field to get their value. It then uses the push() method on the respective arrays to put the current value into the array.
Once it's done, it cals the clearAndShow() function which is responsible for clearing these fields (making them ready for the next round of input), and showing the combined results of the three arrays.
function insert ( ) {
titles.push( titleInput.value );
names.push( nameInput.value );
tickets.push( ticketInput.value );
clearAndShow();
}
This function, as previously stated, starts by setting the .value property of each input to an empty string. It then clears out the .innerHTML of our message box. Lastly, it calls the join() method on all of our arrays to convert their values into a comma-separated list of values. This resulting string is then passed into the message box.
function clearAndShow () {
titleInput.value = "";
nameInput.value = "";
ticketInput.value = "";
messageBox.innerHTML = "";
messageBox.innerHTML += "Titles: " + titles.join(", ") + "<br/>";
messageBox.innerHTML += "Names: " + names.join(", ") + "<br/>";
messageBox.innerHTML += "Tickets: " + tickets.join(", ");
}
The final result can be used online at http://jsbin.com/ufanep/2/edit
You have at least these 3 issues:
you are not getting the element's value properly
The div that you are trying to use to display whether the values have been saved or not has id display yet in your javascript you attempt to get element myDiv which is not even defined in your markup.
Never name variables with reserved keywords in javascript. using "string" as a variable name is NOT a good thing to do on most of the languages I can think of. I renamed your string variable to "content" instead. See below.
You can save all three values at once by doing:
var title=new Array();
var names=new Array();//renamed to names -added an S-
//to avoid conflicts with the input named "name"
var tickets=new Array();
function insert(){
var titleValue = document.getElementById('title').value;
var actorValue = document.getElementById('name').value;
var ticketsValue = document.getElementById('tickets').value;
title[title.length]=titleValue;
names[names.length]=actorValue;
tickets[tickets.length]=ticketsValue;
}
And then change the show function to:
function show() {
var content="<b>All Elements of the Arrays :</b><br>";
for(var i = 0; i < title.length; i++) {
content +=title[i]+"<br>";
}
for(var i = 0; i < names.length; i++) {
content +=names[i]+"<br>";
}
for(var i = 0; i < tickets.length; i++) {
content +=tickets[i]+"<br>";
}
document.getElementById('display').innerHTML = content; //note that I changed
//to 'display' because that's
//what you have in your markup
}
Here's a jsfiddle for you to play around.

Categories

Resources