adding multiple values to single array item in javascript - javascript

I am having trouble with output of an array, I think.
What I would like the output to look like is:
1. FirstName LastName DOB
but what I end up with is:
1. FirstName
2. LastName
3. DOB
Here is what I have so far but I am not seeing what I am doing wrong.
// global variable:
var tasks = [];
// Function called when the form is submitted.
// Function adds a task to the global array.
function addTask() {
'use strict';
// Get the task:
var firstName = document.getElementById('firstName');
var lastName = document.getElementById('lastName');
var dob = document.getElementById('dob');
// numerical value of dob
var dateofBirth = new Date(dob.value);
// Reference to where the output goes:
var output = document.getElementById('output');
// For the output:
var message = '';
if (firstName.value && lastName.value && dob.value) {
// Add the item to the array:
tasks.push(firstName.value, lastName.value, dateofBirth.toString());
// Update the page:
message = '<h2>Persons Entered</h2><ol>';
for (var i = 0, count = tasks.length; i < count; i++) {
message += '<li>' + tasks[i] + '</li>';
}
message += '</ol>';
output.innerHTML = message;
} // End of IF.
// Return false to prevent submission:
return false;
} // End of addTask() function.
// Initial setup:
function init() {
'use strict';
document.getElementById('theForm').onsubmit = addTask;
} // End of init() function.
window.onload = init;
Thanks, I hope this helps you to help me.

tasks.push({firstName: firstName.value, lastName: lastName.value, DOB: dateofBirth.toString()})
And then
tasks[0].firstName will output firstName.value
tasks[0].lastName will output lastName.value
etc..
Edit
Using this, you can then construct your messasge like this :
for (var i = 0, count = tasks.length; i < count; i++) {
message += '<li><span>' + tasks[i].firstName + '</span><span> '
+ tasks[i].lastName + '</span><span>' + tasks[i].DOB + '</span></li>';
}
Of course, the span tags are optionnal but this will allow you to apply a style to each part of the information in your css (width, padding, etc..) and you will always be able to easily select a property of a task by index

Your problem is that you're adding li elements to every element in your array, instead only add teh li once
// Update the page:
message = '<h2>Persons Entered</h2><ol><li>' + tasks.join(' ') + '</li></ol>';
output.innerHTML = message;

Why do you put each element in its own <li>?
If you don't put it in different <li> but in a common one, everything will be fine
message = '<h2>Persons Entered</h2><ol><li>';
for (var i = 0, count = tasks.length; i < count; i++) {
message += tasks[i];
message += " ";
}
message += '</li></ol>';
output.innerHTML = message;

Use Span. you can use Array.join
output.innerHTML= '<h2>Persons Entered</h2><div><span>' + tasks.join("</span> <span>") +"</span>";

You want to add them as an array to the array, not as values to the array
What you have is this:
tasks.push(firstName.value, lastName.value, dateofBirth.toString());
what I think you want is this:
tasks.push([firstName.value, lastName.value, dateofBirth.toString()]);
The answer above is the same, but with an object, not a array.

What you are doing is pushing multiple values into your array. What you want to be doing is to turn the different values into a single value and then push that value into your array. To get the exact output as you were requesting, you can turn these multiple values into one by concatenating them into a string:
Change this:
tasks.push(firstName.value, lastName.value, dateofBirth.toString());
Into this:
tasks.push(firstName.value + ' ' + lastName.value + ' ' + dateofBirth.toString());
However, this does mean you'll lose access to the individual values. If you want access to those, you could instead assemble them into an object:
tasks.push({"firstName" : firstName.value,
"lastName" : lastName.value,
"dateOfBirth" : dateofBirth.toString());

Its a little confusing what you are asking. If you simply want this:
1. FirstName LastName DOB
over this:
1. FirstName
2. LastName
3. DOB
Then your issue is not with the array but with how you are defining the loop code. Try this instead:
// Update the page:
message = '<h2>Persons Entered</h2><ol><li>';
for (var i = 0, count = tasks.length; i < count; i++) {
message += tasks[i] + ' ';
}
message += '</li></ol>';
That way you are putting the array elements in a single list element, rather than across three of them.
EDIT - for Multi-dimensional array traversal
This is assuming that the array is defined this way (per Dan Steingart's answer):
tasks.push([firstName.value, lastName.value, dateofBirth.toString()]);
We then can have the following:
// Update the page:
message = '<h2>Persons Entered</h2><ol>';
for (var i = 0, count = tasks.length; i < count; i++) {
message += '<li> + tasks[i].toString().replace(',',' ') + '</li>';
}
message += '</ol>';
Here you are traversing each element of tasks when each element of tasks is also itself an array. The toString() on an inner array will display the values in a comma separated fashion, then the replace() function simply replaces the comma's with spaces.

Related

How to use join function to sum 2 fields in JavaScript

Can someone help me to sum the 2 fields and display the results in one box by using JavaScript.
var values1 = this.getField("Text6").value.split("\r");
var values2 = this.getField("Text7").value.split("\r");
for(i = 0; i < values1.length ; i++)
{
values1[i] = parseInt(values1[i]) + "\n";
values2[i] = parseInt(values2[i]) + "\n";
this.getField("Text8").value = (values1[i]+values2[i]).join("") ;
}
I am getting the following error:
TypeError: (values1 + values2).join is not a function
You can't join like that, the join method can only be applied on an array.
You can do this:
this.getField("Text8").value = [values1[i], values2[i]].join("");
But a better way:
this.getField("Text8").value = `${values1[i]}${values2[i]}`;
EDIT:
If you want to do a sum, you can simply do this:
this.getField("Text8").value = values1[i] + values2[i];
If you have string instead of a int as values, then you need to cast their values before:
this.getField("Text8").value = parseInt(values1[i]) + parseInt(values2[i]);

How to most efficiently generate string from array of objects in javascript?

I have the following:
var students = [{name:"Jordan", age:"6"},{name:"Jake", age:"7"},{name:"Mark", age:"10"}]
I want to generate a string like this:
"Jordan,6|Jake,7|Mark,10"
What is the most efficient way to do this?
I am currently using:
var studentstr = "";
for(var i = 0; i < students.length; i++) {
studentstr = students['name'] + "," + students['age'] + "|"
}
studentstr = studentstr.substring(0, studentstr.length - 1);
Also, performance-wise, if I had an array of 2,000 items, is it "costly" to perform this transformation? The resulting string contains both keys in the object and not a single join on one object in the property.
You can map each student object to a string and then join them all with |:
var studentstr = students.map(function (student) {
return student.name + ',' + student.age;
}).join('|');
Also, performance-wise, if I had an array of 2,000 items, is it "costly" to perform this transformation?
No.
Yes, using string concatenation in a loop is costly. The string grows for each iteration, and each time you have to copy the entire previous string to create the new version. The execution time of the loop grows exponentially to the number of items.
You can put the string for each object in an array, then join them together:
var students = [{name:"Jordan", age:"6"},{name:"Jake", age:"7"},{name:"Mark", age:"10"}];
var items = [];
for (var i = 0; i < students.length; i++) {
items.push(students[i].name + ',' +students[i].age);
}
var str = items.join('|');
// display result in snippet
document.write(str);
map works well for this:
var students = [{name:"Jordan", age:"6"},{name:"Jake", age:"7"},{name:"Mark", age:"10"}];
var result = students.map(function(student) {
return student.name + ',' + student.age;
});
alert(result.join('|'));
Try this and see your console:
var string = '';
for (var s in students) {
string += students[s].name + ', ' + students[s].age + ' | ';
}
console.log(string);
Fiddle: http://jsfiddle.net/80ss0u14/
I do not think it is costly to go on with such approach. It may be the most efficient way to iterate through the data.

JavaScript: Is this possible? using array value to display the quantity

Given this JavaScript array:
var list = [1,1,1,2,2,2,2]
I want to know how I can produce an HTML list below that has each unique item in the array and number of times that they appear in the array. I just want to know the JavaScript to produce the data, I can generate the HTML.
1 is x3
2 is x4
I'm confused about how to achieve this. Basically, similar to shopping cart quantity functionality, but using the array.
http://jsfiddle.net/37ab3k00/
Use .reduce to reduce your array to an object of quantities.
var list = [1, 1, 1, 2, 2, 2, 2];
var quantities = list.reduce(function(obj, n) {
if (obj[n]) obj[n]++;
else obj[n] = 1;
return obj;
}, {});
var ul = document.querySelector("ul");
for (var n in quantities) {
ul.appendChild(document.createElement("li")).textContent = n + " has a quantity x" + quantities[n];
}
<ul></ul>
The first argument to .reduce() is a function that gets invoked for each member in the Array.
The second argument is an object that we're going to pass along to each iteration. It gets passed as the first argument to the function we provided, and we always return it so that it always gets passed as that argument. This is called the accumulator.
The n argument to the function we provided is the value of the current member in the list. So what we do is first see if our obj has a truthy n member. If so, it must have been encountered already, so we increment it. If not, we assign it the initial value of 1 to represent the first n that was found for that value.
var list = [1,1,1,2,2,2,2]
var counts = {};
for (var i = 0; i < list.length; i++) {
counts[list[i]] = 1 + (counts[list[i]] || 0);
}
Demo: http://jsfiddle.net/famn4zcL/2/
Add to HTML
var li = '';
for (var el in counts) {
li += '<li>' + el + ' is x' + counts[el] + '</li>';
}
document.getElementById('list').innerHTML = li;
Demo: http://jsfiddle.net/famn4zcL/3/
Another way would be using array of objects (those can be easily upgraded with additional data that you probably would need building products), like so:
HTML:
<span id="display"></span>
JS (plain, no Framework):
var objects = [
{prod:0,quant:00},
{prod:1,quant:11},
{prod:2,quant:22},
{prod:3,quant:33},
{prod:4,quant:44},
{prod:5,quant:55}
];
var list_of_objects = "", display_id = document.getElementById("display");
for (var key in objects) {
if (objects.hasOwnProperty(key)) {
console.log(key);
list_of_objects += '<li>'+objects[key].prod + ' has a qtty x ' + objects[key].quant+'</li>';
}
}
console.log(list_of_objects);
display_id.innerHTML = list_of_objects;
So you could easily upgrade product data with new info, like:
var objects = [
{prod:0,quant:00,url:"http://url00"},
{prod:1,quant:11,url:"http://url11"},
{prod:2,quant:22,url:"http://url22"},
{prod:3,quant:33,url:"http://url33"},
{prod:4,quant:44,url:"http://url44"},
{prod:5,quant:55,url:"http://url55"}
];
JSfiddle to play with: http://jsfiddle.net/7hokfmdu/

Is this a scope issue or am I setting up my array of objects incorrectly?

I am having some problems with two objects in my javascript code.
My first object is from an API call which I haven't listed here, but the data variable being passed into my getStudentStats() function is the result of that API call and its output can be seen in the image below highlighted [1]. It is a list of students and their associated data.
My second object is the result of a JSON call which can be seen below (the UWA.Data.getJson() function). Its output can be seen in the image below highlighted [2]. It is a list of students' IDs and some statistics from my local database, i.e. the number of flags they've received and the number of interventions that have been raised for them.
getStudentStats : function(data) {
/* [1] Console log */
console.log(data);
var student_list = '';
for( var i = 0; i < data.length; i++ )
student_list += data[i].id + ',';
student_list = student_list.substring(0, student_list.length - 1);
var Students = [];
var Student_Data = data;
UWA.Data.getJson(FLAGS_Assign_Flags.url + 'get_students_stats&arg=' + student_list, function(data) {
/* [2] Console log */
console.log(data);
for( var i = 0; i < data.length; i++ ) {
var Student_ID = data[i].Student_ID;
var obj = { 'flags': data[i].Flags, 'interventions': data[i].Interventions };
Students[Student_ID] = obj;
}
/* [3] Console log */
console.log(Students);
FLAGS_Assign_Flags.displayStudents(Students, Student_Data);
});
},
What I'm trying to do is, basically, display some information from both of these objects (using jQuery .html() and a string variable).
displayStudents : function(students, data) {
/* Set up our HTML variable which we'll .html() when it's populated */
var StudentsHTML = '<ul id="students_display">';
for( var i = 0; i < data.length; i++ ) {
/* For each student in the `data` object, grab their ID to access the correct element in the students object */
var id = data[i].id;
/* Set up a variable which we'll use to display the students' stats in our LI */
var stats = '<div>';
/* If the student doesn't have any flags or interventions, manually set the text */
if( typeof students[id] != 'undefined' )
stats += ' (F:<span class="f">' + students[id].Flags + '</span>|I:<span class="i">' + students[id].Flags + '</span>)';
else
stats += ' (F:<span class="f">0</span>|I:<span class="i">0</span>)';
stats += '</div>';
/* Produce checkbox, name and stats for each student and add them to the HTML variable */
StudentsHTML += '<li><input type="checkbox" name="students" value="' + data[i].id + '" /> ' + data[i].firstname + ' ' + data[i].surname + stats + '</li>';
}
StudentsHTML += '</ul>';
/* Set the HTML... */
$('#students').html(StudentsHTML);
/* Do some other stuff not relevant to this question! */
FLAGS_Assign_Flags.displayForm();
},
The problem is, as you can see in the image below highlighted [3], my Students object appears as a load of garbage in console and I can't access any information from it.
Is this a scope issue, or am I setting up my array of objects incorrectly?
You have created var Students = []; as an array, and are later using it as an associative array to assign values to it:
Students[Student_ID] = obj;
This will not work, you should create the Students var as an object:
var Students = {};
Javascript does not have a notion of 'associative arrays', and you should use basic objects for this purpose.
Later on, you can loop through these with for in, too safely use for in, combine it with a call to hasOwnProperty:
for (var i in Students) {
if (!Students.hasOwnProperty(i)) continue; // skip inherited properties
// i == StudentID
// Students[i] == your student object
}
Students[Student_ID] = obj;
Is probably the problem.
For example:
var arr = [];
arr[4] = {};
=>
[undefined × 4, Object]

textarea duplicate string check ignoring leading and trailing whitespace

Users will enter various serials in a textarea. Each newline will indicate a new serial. Some requirements/restrictions:
Leading and trailing white spaces are not allowed.
White space within a serial is okay.
Blank serials are not allowed
I'd prefer to not use JQuery.
Store duplicates so they can be shown to the user.
Based on my tests I have a working solution. I want to make sure I'm not missing or overlooking anything. My questions are:
Is there a more efficient ways to check for duplicates?
Are there any glaring test cases that my solution won't catch?
Working Example: http://jsbin.com/ivusuj/1/
function duplicateCheck() {
var output = document.getElementById('Output');
output.innerHTML = '';
var duplicateSerials = [];
var count = 0;
var textArea = document.getElementById('Serials');
var serials = textArea.value.trim().split(/ *\n */);
for(var i = 0;i < serials.length;i++){
var serial = serials[i];
if(serials.indexOf(serial) != serials.lastIndexOf(serial) &&
duplicateSerials.indexOf(serial) == -1 && serial !== '') {
duplicateSerials.push(serial);
}
}
// For testing
output.innerHTML = '<pre>Serials:\t' + serials.toString() + "<br />" +
'Duplicates:\t' + duplicateSerials.toString() + "<br>" +
'</pre>';
}
Note: the above is for a client side check. The same check will be performed server side as well to ensure the data is valid.
Update
Solution comparison: http://jsbin.com/ivusuj/4/edit
I put together a jsfiddle her: http://jsfiddle.net/wrexroad/yFJjR/3/
Actually checking for duplicates that way is pretty inefficient.
Instead of checking for duplicates, this just adds a property to an object where the property's name is is the serial. Then it prints out all of the property names.
This way if you have duplicates, it will just create the property, then overwrite it.
Here is the function:
function duplicateCheck() {
var output = document.getElementById('Output');
output.innerHTML = '';
var textArea = document.getElementById('Serials');
var inputSerials =
textArea.value.trim().split(/ *\n */);
var outputSerials = new Object();
for(var i = 0;i < inputSerials.length;i++){
var serial = inputSerials[i];
//build an object whose properties are serials
//if the serial exists, incremint a counter
if(outputSerials[serial]){
outputSerials[serial]++;
}else{
outputSerials[serial] = 1;
}
}
output.innerHTML =
'Serials: <br />';
for(var i in outputSerials){
output.innerHTML += i + " ";
}
output.innerHTML +=
'<br /><br />Duplicate Serials: <br />';
for(var i in outputSerials){
//check to see if we have any duplicates
if(outputSerials[i] > 1){
output.innerHTML += i + " ";
}
}
}
I think you'd get significantly better performance if you used an object to determine which serials you'd seen before. Something closer to this:
var seen = {};
for (var i = 0, j = serials.length; i < j; ++i) {
var serial = serials[i];
if (seen.hasOwnProperty(serial)) {
// Dupe code goes here.
continue;
}
// Can't be a duplicate if we get to this point.
}
Though that won't work with serials that use periods.
Here's a solution to filter out duplicates.
function formatInput() {
var arrUnique = [], dups = [],
str = document.getElementById('Serials').value
.replace(/\r\n?/g,'\n')
// normalize newlines - not sure what PC's
// return. Mac's are using \n's
.replace(/(^((?!\n)\s)+|((?!\n)\s)+$)/gm,'')
// trim each line
.replace(/^\n+|\n+$|\n+(?=\n(?!\n))/g,''),
// delete empty lines and trim the whole string
arr = str.length ? str.split(/\n/) : [];
// split each line, if any
for (var i = 0; i < arr.length; i++) {
if (arrUnique.indexOf(arr[i]) == -1)
arrUnique.push(arr[i]);
else dups.push(arr[i]);
}
//document.getElementById('Serials').value = arrUnique.join('\n');
console.log('serials:', arr);
console.log('unique:', arrUnique);
console.log('duplicates:', dups);
}

Categories

Resources