Javascript program keeps outputting wrong index of array - javascript

I'm trying to finish an assignment, I'm stuck at and can't find a solution.
Below is my full code.
//Student Object
var student = {
f_name: "",
l_name: "",
s_numb: "",
email: "",
courses: [],
/*This function returns if current object has a specific course
and returns true if it does and false if not.*/
hasCourse: function (course) {
for (var c = 0; c < this.courses.length; c++) {
if (course == this.courses[c]) {
return true;
}
}
return false;
}
};
/*This function returns name with first letter
capitalized and the rest lowercase.*/
function formatingName(name) {
return name.charAt(0).toUpperCase() + name.substr(1, name.length);
}
/*This function validates to match the Student ID pattern and
returns true it matches and false if not.*/
function validateStudentID(sid) {
var patt = /^([0-9]{3}[.]){2}[0-9]{3}$/;
return patt.test(sid);
}
/*This function receives a string array of course codes which
are to be registered for a student. The function returns an empty
string indicating all course codes in the array are valid; otherwise
the function returns the first invalid course code in the array.*/
function validateCourses(courses) {
var error = false;
for (i = 0; i < courses.length; i++) {
if (error == false) {
if (courses[i] != "APC100" && courses[i] != "IPC144" &&
courses[i] != "ULI101" && courses[i] != "IOS110" &&
courses[i] != "EAC150" && courses[i] != "IBC233" &&
courses[i] != "OOP244" && courses[i] != "DBS201" &&
courses[i] != "INT222") {
error = courses[i];
break;
}
}
}
if (error != false) {return error;} else {return "";}
return '';
}
var response = true; //Continues to prompt if error is true
var error = false; //Error flag
var temp_obj = []; //Temporary object that hold current object's values
var temp_course = [];
var students = [];
var x = 0;
while (response == true) {
do {
var str = prompt("Please enter first name, last name, student ID,\nemail and courses (separated by ',')");
if (str == "" || str === null) {
response = false;
break;
}
//Removing white spaces in the string
str = str.split(' ').join('');
//Splitting the string into array by , (coma) and assigning it to temporary object array
temp_obj = str.split(',');
//Validating Student ID
if (validateStudentID(temp_obj[2]) == false) {
alert(temp_obj[2] + " is not a valid student ID, Please use xxx.xxx.xxx format.\nPlease try again!");
error = true;
}
//Validating if student is registered in atleast 1 course.
if (temp_obj.length < 5) {
alert("A student must be registered in at-least 1 course");
error = true;
}
//Checking if student is registered in more than 6 courses
if (temp_obj.length > 10) {
temp_obj = temp_obj.slice(0,9);
}
//Extracting courses from temporary object array
temp_course = temp_obj.slice(4, temp_obj.length);
//Makking all the courses uppercase
for (i = 0; i < temp_course.length; i++) {
temp_course[i] = temp_course[i].toUpperCase();
}
//Validating if courses are valid
if (validateCourses(temp_course) != "") {
alert(validateCourses(temp_course) + " is not the course provided by CPD program!\nPlease try again.");
error = true;
}
}
while (error == true);
//Break out of loop if user submitted nothing or if user pressed cancel
if (response == false) {break;}
//Merging cources array back with temporary object array
temp_obj = temp_obj.concat(temp_course);
//Creating a new instance of a student
students[x] = Object.create(student);
//Assigning values to student object from temporary object;
students[x].f_name = formatingName(temp_obj[0]); //Formatting name
students[x].l_name = formatingName(temp_obj[1]);
students[x].s_numb = temp_obj[2];
students[x].email = temp_obj[3].toLowerCase(); //Making the email all lowercase
//Making the course codes in Uppercase
for (i = 0; i < (temp_obj.length) - 4; i++ ) {
students[x].courses[i] = temp_obj[i + 4].toUpperCase();
}
x++;
}
//Printing total registered students
alert("There are total " + students.length + " students registered.");
var R_fname = [];
var R_lname = [];
var R_sid = [];
var R_email = [];
do {
var no_error = false;
var query = true;
var query_course = [];
while (no_error == false) {
query = prompt("Please enter a course code:");
if (query == "" || query == null) {
query = false;
break;
}
no_error = true;
query_course[0] = query.toUpperCase();
if (validateCourses(query_course) != "") {
alert(query + " is not the course provided by CPD program!\nPlease try again");
no_error = false;
}
}
if (query == false) {break;}
//THIS IS WHERE I THINK THE PROBLEM IS
//THIS IS WHERE I THINK THE PROBLEM IS
//THIS IS WHERE I THINK THE PROBLEM IS
//THIS IS WHERE I THINK THE PROBLEM IS
for (var a = 0; a < students.length; a++) {
//Checking if student is registred in a course
if (students[a].hasCourse(query_course) == true) {
//Assigning values to temporary array.
R_fname[a] = students[a].f_name;
R_lname[a] = students[a].l_name;
R_sid[a] = students[a].s_numb;
R_email[a] = students[a].email;
}
}
var fin_str = "";
//Concatenating all the students in a specific course to fin_str as string.
for (var b = 0; b < R_fname.length; b++) {
fin_str += (R_fname[b] + " " + R_lname[b] + " " + R_sid[b] + " " + R_email[b] + " \n");
}
//Printing list of student in a specific course
alert("List of students registered in " + query + "\n\n" + fin_str);
//Retting temporary arrays
R_fname.length = 0;
R_lname.length = 0;
R_sid.length = 0;
R_email.length = 0;
//Confirms to Exit the query loop
if (confirm("Click 'OK' to continue to query class lists.\nClick 'Cancel' to stop the program.") == false) {break;}
}
while (query != false);
These are the test values:
roy,bean,056.171.486,rbean#example.ca,int222
carl,bell,121.126.536,cbell#example.ca,dbs201,int222
eric,brand,046.123.976,ebrand#example.ca,oop244,dbs201,int222
henry, clay, 034.146.412, hclay#example.ca , ibc233 , oop244 , dbs201 , int222
When the program asks to enter the course code; it is suppose to see if the students have that course and only if they do, it prints that students info.
In my case, even if student does not have the course it still prints it.
Please run the code to see if it makes more sense... I can't explain any better

The problem can be reduced to this:
var Foo = {
courses: []
};
var x = Object.create(Foo);
var y = Object.create(Foo);
x.courses.push(123);
alert(y.courses[0]); // "123"
The reason for this behaviour is that both objects inherit the same prototype and any changes made to .courses will apply to both objects.
For this reason, it would be better to create a constructor function instead:
function Foo()
{
this.courses = [];
}
var x = new Foo();

Related

Array in localStorage is not initialized at first run

window.reload = () => {
var userArray = JSON.parse(localStorage.getItem("key"));
}
let feedback = document.getElementById("feedback");
function checkemail(userArray, email) {
var i;
if (userArray == null | undefined) {
userArray = JSON.parse(localStorage.getItem("key"));
}
var person = {
name: document.getElementById("nameinput").value,
email: document.getElementById("emailinput").value,
passowrd: document.getElementById("passwordinput").value
};
let isFound = false;
for (i = 0; i < userArray.length; i++) { //here is the error it still happen even after I added the if null part
if (userArray != undefined)
var oldemail = userArray[i].email;
let newemail = document.getElementById("emailinput").value;
if (newemail === oldemail) {
isFound = true;
i = userArray.length;
return feedback.innerHTML = "email exist please log in or register with different email";
}
}
if (!isFound) {
return storeName(person, userArray);
}
}
function storeName(person, userArray) {
if (userArray != undefined)
var person = {
name: document.getElementById("nameinput").value,
email: document.getElementById("emailinput").value,
passowrd: document.getElementById("passwordinput").value
};
userArray = JSON.parse(localStorage.getItem("key"));
userArray.push(person);
userArray = JSON.stringify(userArray);
localStorage.setItem("key", userArray);
console.log(userArray);
}
I want to store an array in local storage, the first time when I run the code, of course, the array is empty and I can not use a loop for example because I can't call (array.length).
so can I tell the compiler for example if the array is null or undefined just put length is zero or assign the value of the array to an empty array?
can I do something like this?
if( userArray == null | undefined) { userArray = JSON.parse(localStorage.getItem("key")); }
function checkemail(userArray, email) {
if (userArray == null || typeof(userArray) == 'undefined') {
userArray = [];
}
// rest of the code
}
This might be working too:
userArray ??= [];

cookies are returning undefined

So i'm trying a simple cookie exercise and when i hit submit it returns undefined. Also is there a way to check what in a cookie in visual studio code?
function setcookie()
{
var tmr = new Date();
tmr.setDate(tmr.getDate() + 1);
document.cookie = "username="+ document.getElementById("username").innerHTML +";path=/";
document.cookie = "password="+ document.getElementById("password").value +";path=/";
}
function getcookie()
{
var Carray = document.cookie.split(";");
for(i = 0 ; i < Carray.length ; i++)
{
var valuearray =Carray[i].split("=")
if (valuearray == "username")
{
var name = valuearray[1];
}
else if (valuearray == "password")
{
var password = valuearray[1];
}
}
alert("username is " + name +" password is " + password);
}
valuearray will be a array, so you need to check valuearray[0] in the if condition.
var valuearray = Carray[i].split("=")
if (valuearray[0] == "username"){ //Here, valuearray[0]
var name = valuearray[1];
} else if (valuearray[0] == "password"){
var password = valuearray[1];
}
Try this
function getcookie() {
const Carray = document.cookie.split(";");
const [name, password] = Carray.map(item => item.split('=')[1])
console.log("username is " + name +" password is " + password);
}
or if you want to transform your cookies into object use this code
function getcookie()
{
var Carray = document.cookie.split(";");
var cookieObj = Carray.reduce((cookieObj, current) => {
const [key, value] = current.split('=');
return { ...cookieObj, ...{ [key]: value } }
}, {})
console.log("username is " + cookieObj.username +" password is " + cookieObj.password);
return cookieObj;
}
// result
{
username: 'usersname'
password: 'userspassword'
}
Please return your result from the functions, I'm not returning anything because I'm trying to match your code.
and answer to your second question. yes you can get value from vscode but for that you need to start your debugging mode
name and password are declared in the block of for, but you use them in out of the block.
change getcookie function to this:
var name="";
var password ="";
for(i = 0 ; i < Carray.length ; i++)
{
var valuearray =Carray[i].split("=")
if (valuearray == "username")
{
name = valuearray[1];
}
else if (valuearray == "password")
{
password = valuearray[1];
}
}
alert("username is " + name +" password is " + password);

JavaScript. Please advise on better code reuse and/or structure

As the title suggests, A better coding structure or implementation for my JavaScript below. This checks a ID element values from a form before submitting to a database.
I'm interested to know if I could have reduced the code size/could have implemented reuse of code which will give me some tips for the future!
Thanks.
function validateRunnerID()
{
var runnerID = document.getElementById('RunnerID').value;
if (isNaN(runnerID) || runnerID < 1 || runnerID > 9999)
{
return "RunnerID: Enter a Integer Value between 1-9999 \n\n";
}else{
return "";
}
}
function validateEventID()
{
var eventID = document.getElementById('EventID').value;
if (isNaN(eventID) || eventID < 1 || eventID > 9999)
{
return "EventID: Enter a Integer Value between 1-9999 \n\n";
}else{
return "";
}
}
function validateDate()
{
var checkDate= /^[0-9]{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])/;
var date= document.getElementById('Date');
var tof= date.value.match(checkDate);
return tof? "" : "Date: Enter a Valid Date with parameters: YYYY-MM-DD \n\n";
}
function validateFinishTime()
{
var finishTime = document.getElementById("FinishTime").value;
if (finishTime.match(/^[0-9]{2}:[0-9]{2}:[0-9]{2}$/))
{
return ""
}else{
return "Finish Time: Enter a valid Time with parameters: HH:MM:SS \n\n";
}
}
//
//
function validatePosition()
{
var position = document.getElementById('Position').value;
if (position.length == 0)
{
document.getElementById('Position').value = -1;
return "";
}else{
return "";
}
}
function validateCategoryID()
{
var categoryID = document.getElementById('CategoryID').value;
if (categoryID.length == 0)
{
document.getElementById('CategoryID').value = -1;
return "";
}else{
return "";
}
}
function validateAgeGrade()
{
var ageGrade = document.getElementById('AgeGrade').value;
if (ageGrade.length == 0)
{
document.getElementById('AgeGrade').value = -1;
return "";
}else{
return "";
}
}
function validatePB()
{
var pBest = document.getElementById('PB').value;
if (pBest.length == 0)
{
document.getElementById('PB').value = 0;
return "";
}else{
return "";
}
}
//
//
function validateForm()
{
var result = validateRunnerID() + validateEventID() + validateDate() + validateFinishTime() + validatePosition() + validateCategoryID() + validateAgeGrade() + validatePB();
if ( result == "" )
{
alert("Data Accepted and Submitted \n\n");
return true;
}else{
alert("Please Fix Errors Listed: \n\n" + result);
return false;
}
}
One thing you can do is to accept an elementId as input to your validation functions. This allows to reuse the same logic for different fields.
For example:
function validate4DigitInt(elementId)
{
var value = document.getElementById(elementId).value;
if (isNaN(value) || value < 1 || value > 9999)
{
return elementId + ": Enter a Integer Value between 1-9999 \n\n";
}else{
return "";
}
}
Now you can validate both RunnerId and EventId using the same function:
var result="";
result+=validate4DigitInt("RunnerId");
result+=validate4DigitInt("EventId");

Search, count duplicated strings and add for each numbers

I have a script that is searching for duplicated text strings in an array and changing the colors.
function checkDuplicates() {
var values = new Array();
var $input = $('input[type=\'text\']');
var error = 0;
$input.each(function() {
$(this).removeClass('double-error');
var that = this;
if (that.value!='') {
values[that.value] = 0;
$('input[type=\'text\']').each(function() {
if (this.value == that.value) {
values[that.value]++;
}
});
} //endif
});
$input.each(function(key) {
if (values[this.value]>1) {
error++;
$(this).addClass('double-error');
}
});
return (error <= 0); //returns false or true
}
<style type="text/css">
.double-error {
color:red;
border:1px solid red;
}
</style>
This is working fine.
However, I need to count duplicated strings and add keep track of whether they are the first occurence of that word, the second occurence of that word, etc.
For example:
Given john, john, peter, doe, peter, john, the result would be john-1, john-2, peter-1, doe, peter-2, john-3.
This is what I currently have:
function eliminateDuplicates() {
var values = new Array();
var $input = $('input[type=\'text\']');
var error = 0;
$input.each(function() {
$(this).removeClass('double-error');
var that = this;
if (that.value!='') {
values[that.value] = 0;
$('input[type=\'text\']').each(function() {
if (this.value == that.value) {
values[that.value]++;
}
});
}
});
$input.each(function(key) {
if (values[this.value]>1) {
error++;
myArray = values[this.value];
for (var i = 0; i < myArray; i++) {
$(this).parent()
.find('input[type=\'text\']')
.val(this.value + '-' + i);
}
}
});
return error <= 0; //return error > 0 ? false : true;
}
But I got this result:
john-0-1-2, john-0-1-2, peter-0-1, doe, peter-0-1, john-0-1-2
What's wrong?
I make some modification:
function eliminateDuplicates() {
var values = new Array();
var $input = $('input[type=\'text\']');
var error = 0;
$input.each(function() {
$(this).removeClass('double-error');
var that = this;
if (that.value!='') {
values[that.value] = 0;
$('input[type=\'text\']').each(function() {
if (this.value == that.value) {
values[that.value]++;
}
});
}
});
$input.each(function(key) {
if (values[this.value]>1) {
var name=this.value;
var names = values[this.value];
values[this.value]++;
for (var i = 0; i < names; i++){
$(this).parent().find('input[type=\'text\']').val(name + '-' + i);
}
}
});
checkDoubles();
return error <= 0; //return error > 0 ? false : true;
}
now I getting counts in sequence but not from 1.
for example if I have 4 duplicated names (Peter) i getting:
Peter-3, Peter-4, Peter-5, Peter-6.
but I need
Peter-1, Peter-2, Peter-3, Peter-4.
what wrong?
I think you're looking for something like this:
function eliminateDuplicates() {
var repeats = {};
var error = false;
//cache inputs
var $inputs = $("input[type='text']");
//loop through inputs and update repeats
for (i = 0; i < $inputs.length; ++i) {
//cache current element
var cur = $inputs[i];
//remove class
$(cur).removeClass("double-error");
//get text of this element
var text = $(cur).val();
//no text -- continue
if (text === "") {
continue;
}
//first time we've came across this value -- intialize it's counter to 1
if ((text in repeats) === false) {
repeats[text] = 1;
}
//repeat offender. Increment its counter.
else {
repeats[text] = repeats[text] + 1;
}
//update the the value for this one
$(cur).val(text + "-" + repeats[text]);
}
return error; // always returns false since I'm not sure
// when it's supposed to return true.
}
PS: I didn't understand when error was supposed to be true, so it's always false. Nevertheless, this should be enough to get you going.
PPS: Plunker here.

How to show if date is invalid in javascript

This is what I tried so far but still nothing changed. I don't where to start to maybe someone professional can help me get through with this. This is for validation purposes.
Code:
$(function(){
var len = $('#groupContainer > div').length;
var arr = [];
for(var i=0; i < len; i++){
var number = $('#number_' + [i + 1]);
var date = $('#date_' + [i + 1]);
var count = i + 1;
var message ="";
console.log(number)
var a = number.map(function(){
return this.value;
});
var b = date.map(function(){
return this.value;
});
var newObj = {number: a[0], date: b[0]}
arr.push(newObj);
}
var messages={};
var message="";
for(var c = 0; c < arr.length; c++)
{
var groupMessage=false;
for(var d in arr[c])
{
if(arr[c].hasOwnProperty(d))
{
if(arr[c][d] == "")
{
if(messages[d]==undefined) {
messages[d]={groups:[]};
}
messages[d].groups.push(c+1);
}
}
}
}
var lastgroup=""
for(i in messages){
m = messages[i];
var date = $('#date_' + i);
console.log(date)
if(m.groups.join(",")==lastgroup) {
message = message.replace("Group "+m.groups.join(",")+" ","Group "+m.groups.join(",")+":\n");
if(m == "Date" && date.length != 8)
{ message += i + ' is invalid!\n';
}
message+=i+" is required!\n";
}else {
message+="Group "+m.groups.join(",")+" "+i+" is required!\n";
}
lastgroup = m.groups.join(",");
}
if(message)
{
alert(message);
}
});
Fiddle
If all field is not filled show:
Group 1, 2 Number is required!
Group 1, 2 Date is required!
Valid date must be mm/dd/yy
And if date is not really a date:
Group 1, 2 Date is invalid.
And if one of the inputs is invalid.
Group 2 Date is invalid.
If all field is filled do nothing.
I recommend categorize objects by class, example:
.txtNumber for Number
.txtDate for date
You can use regExpAllow for keypress event and regexpMatch for the submit validation.
KeyPress Validation
$(document).on('keyup','.txtDate', function() {
var regExpAllow = new RegExp('[^0-9/]', 'g');
$(this).val($(this).val().replace(regExpAllow,''));
});
$(document).on('keyup','.txtNumber', function() {
var regExpAllow = new RegExp('[^0-9.]', 'g');
$(this).val($(this).val().replace(regExpAllow,''));
});
Submit Validation
$(document).on('click','#btnSubmit', function() {
var regExpMatch = new RegExp('^[0-3][0-9]/[0-1][0-9]/[1-2][0-9]{3}$');
$('.txtDate').each(function() {
if ($(this).val().match(regExpMatch) != null) {
alert('Valid Date:'+$(this).val());
} else {
alert('Invalid Date:'+$(this).val());
}
});
regExpMatch = new RegExp('^[0-9].[0-9]{3}$');
$('.txtNumber').each(function() {
if ($(this).val().match(regExpMatch) != null) {
alert('Valid Number:'+$(this).val());
} else {
alert('Invalid Number:'+$(this).val());
}
});
});
JSFiddle example: http://jsfiddle.net/BernardoBJ/o5dbnt51/4/
With this you can validate that characters can be entered and how it will be your final result (You can also validate the same way the regular expression of numbers if you want).
Implements this logic in your code.
note: gets a value that properly validate dates and your numbers format.
All that mapping and looping is hard to follow...just loop through the elements once and deal with each type within the loop
function validate(){
var errors = false,
$cont = $('#groupContainer');
// remove prior errors
$cont.find('.error').remove();
// loop over inputs
$cont.find(':input').each(function () {
// use id to sort out type
var type = this.id.split('_')[0],
value = this.value,
msg = null;
if (!value) {
msg = 'This is required';
} else if (type === 'date') {
if (/**** your invalid date method ***/ ) {
msg = 'Invalid Date';
}
} else if (type === 'number') {
if (isNaN(+value)) {
msg = 'Not a number';
}
}
if (msg) {
errors = true;
$(this).after('<span class="error">' + msg + '</span>')
}
});
return !errors;
}
alert( validate() ? 'Form is valid' :'Oooops! Not valid');
It's up to you to do date validation as no format was given
DEMO

Categories