logging array item by index returning undefiened - javascript

I was making a program that recoreded every keypress and pushed it to an array and it works fine. The problem is when I try to access the first element of the array and log it, it prints undefined. But the whole array logs fine.Why is it printing undefiened? I have added both console log of the array and the array item in my code and have commented besides them to indicate. Any help is appreciated. Thanks in advance.
EDIT: turn out what doesn't work is accessing the last item. I have updated the code above
var cacheW = []
var cacheA = []
var cacheD = []
var cacheS = []
// (B1) CAPTURE KEY STROKES
window.addEventListener("keydown", function(evt) {
if (evt.key == "w") {
cacheW.push('w');
//console.log("this: " + evt.key)
} else if (evt.key == "a") {
cacheA.push('a');
//console.log("this: " + evt.key)
} else if (evt.key == "d") {
cacheD.push('d');
//console.log("this: " + evt.key)
} else if (evt.key == "s") {
cacheS.push('s');
//console.log("this: " + evt.key)
}
});
window.addEventListener("keyup", function(evt) {
if (evt.key == "w") {
cacheW.push("!w");
//console.log("this: " + evt.key + " removed")
} else if (evt.key == "a") {
cacheA.push("!a");
//console.log("this: " + evt.key + " removed")
} else if (evt.key == "d") {
cacheD.push("!d");
//console.log("this: " + evt.key + " removed")
} else if (evt.key == "s") {
cacheS.push("!s");
//console.log("this: " + evt.key + " removed")
}
});
//works
setInterval(function() {
console.log(cacheW) //logs an array
}, 50)
//doesn't work
setInterval(function() {
console.log(cacheW[-1]) //logs undefined, should have logged the last element
}, 50)

Javascript access array items by their index. -1 is an invalid index. To access the last item, use arr[arr.length - 1].
Other languages such as python offer syntactic sugar to access items from the end of an array. JavaScript does not have such syntactic sugar. The closest which you can get is to write arr.slice(-1)[0], but this will create a temporary single-item array and then access the first item of this array.
In fact -1 is a property, not a valid index. Property names are first stringified, then added to the object (every array is an object):
a = [];
a[-1] = 42;
console.log(a); // [], array itself is still empty
console.log(a[-1]); // 42, property -1 on the object has value assigned
console.log(a['-1']); // 42, object property keys are always converted to string first

Instead of this:
//doesn't work
setInterval(function() {
console.log(cacheW[0])//logs undefined, should have logged the first element
}, 50)
This:
setInterval(function() {
if (cacheW.length > 0) {
console.log(cacheW[0]);
} else {
console.log("<empty>");
}
}, 50);
Update
If you want to print the last item:
setInterval(function() {
if (cacheW.length > 0) {
console.log(cacheW[cacheW.length-1]);
} else {
console.log("<empty>");
}
}, 50);

Related

Replace multiple if statements with loop?

Can this code be shortened by looping through the array and replacing the number in input[name="shelf-1"] instead of having multiple if statements?
if(com_array[0] == "ON")
{
$('input[name="shelf-1"]').bootstrapSwitch('state', true);
}else{
$('input[name="shelf-1"]').bootstrapSwitch('state', false);
}
if(com_array[1] == "ON")
{
$('input[name="shelf-2"]').bootstrapSwitch('state', true);
}else{
$('input[name="shelf-2"]').bootstrapSwitch('state', false);
}
if(com_array[3] == "ON")
{
$('input[name="shelf-3"]').bootstrapSwitch('state', true);
}else{
$('input[name="shelf-3"]').bootstrapSwitch('state', false);
}
Assuming that you want to do this for all elements inside the array, you can use a forEach loop as so:
com_array.forEach( (element, index) => {
if(element == "ON") {
$(`input[name="shelf-${index + 1}"]`).bootstrapSwitch('state', true);
}else{
$(`input[name="shelf-${index + 1}"]`).bootstrapSwitch('state', false);
}
})
Updated for refactoring option:
If you want it to be cleaner and less repetitive, you can do away with the if-else statement, and use "element == 'ON' as the condition inside bootstrapSwitch:
com_array.forEach( (element, index) => {
$(`input[name="shelf-${index + 1}"]`).bootstrapSwitch('state', element == "ON");
})
And then you can refactor further to one line
com_array.forEach((element, index) => $(`input[name="shelf-${index + 1}"]`).bootstrapSwitch('state', element == "ON"))
com_array.forEach(function(com, index) {
$('input[name="shelf-' + (index + 1) + '"]').bootstrapSwitch(
'state',
com == 'ON'
)
}
);
I made it IE-11 compatible (i.e. no arrow functions and string template literals). Because I assume you have no transpilation step.
For the non-IE compatible answer (modern js) check the first comment to the question with code.
You could create a function and reuse it:
const bootstrapSwitch = (key, value) = {
$(`input[name="shelf-${key}"]`).bootstrapSwitch('state', value);
}
bootstrapSwitch(0, com_array[1] == "ON")
bootstrapSwitch(1, com_array[2] == "ON")
bootstrapSwitch(3, com_array[3] == "ON")
You can replace the numbers using the index of the array.
let com_array = ['ON','OFF','ON'];
for (index = 0; index < com_array.length; index++) {
if (com_array[index] === 'ON') {
$('input[name="shelf-'+(index+1)+'"]').bootstrapSwitch('state', true);
} else {
$('input[name="shelf-'+(index+1)+'"]').bootstrapSwitch('state', false);
}
}

prevent function from recalling itself at the last statement of the function in java script

I've been learning javascript and jquery and I've encountered a problem when I'm trying to validate my form fields using a jquery function. The problem is its working fine the first two times it is called (when I press the update button for a specific element )and whenever I'm trying to call it a third time (by pressing the update button for the same element as earlier ) it is calling itself but I clearly did not mention any recursive calls and am not calling it within the function again. I'm not sure why it is calling itself. Kindly help me out. I will be attaching the fiddle. After triggering reset in main.updateData(Object.assign({}, main.newObject), keys); in the third time its showing the name empty error which shouldn't be happening.
I've tried giving breakpoints and inspecting the reason behind this weird behaviour but I couldn't
The name field should show an error only when it is empty but third time it is showing error even when it is not empty
FIDDLE
validateFormData: function(value, keys, idCount) {
var keyIndex = 0;
main.newObject[keys[keyIndex++]] = idCount;
if (value == "update") {
main.newObject[keys[0]] = $(".active-contact").attr('id');
//alert("new updated id is " + main.newObject[keys[0]]);
}
var validElementsCount = 0;
var alphabet_pattern = /^[a-z]+\s*/i;
var email_pattern = /[a-z]{0,}[0-9]{0,4}[.]{0,1}[0-9]{0,4}[a-z]{0,8}[0-9]{0,4}[#][a-z]{0,20}[.](com)/i;
var number_pattern = /^[0-9]{10}$/;
var website_pattern = /^(www)[.][a-z]{1,20}[.](com)$/i;
/*Validating the form inputs against the regex pattern*/
if ($("#employee-name").val() == "") {
$("#employee-name-error").text("name cannot be empty");
} else if (!alphabet_pattern.test($("#employee-name").val())) {
$("#employee-name-error").text("Only alphabets are allowed");
} else {
validElementsCount++;
$("#employee-name-error").text("");
main.newObject[keys[keyIndex++]] = $("#employee-name").val();
//alert("object is " + JSON.stringify(main.newObject[keys[keyIndex-1]]) + " key is " + keys[keyIndex-1]);
}
//employee email validation
if (email_pattern.test($("#employee-email").val()) || $("#employee-email").val() == "") {
$("#employee-email-error").text("");
validElementsCount++;
main.newObject[keys[keyIndex++]] = $("#employee-email").val();
//alert("object is " + JSON.stringify(main.newObject[keys[keyIndex - 1]]) + " key is " + keys[keyIndex - 1]);
} else {
$("#employee-email-error").text("Follow email pattern");
}
//employee mobile validation
if (number_pattern.test($("#employee-mobile").val()) || $("#employee-mobile").val() == "") {
$("#employee-mobile-error").text("");
validElementsCount++;
main.newObject[keys[keyIndex++]] = $("#employee-mobile").val();
//alert("object is " + JSON.stringify(main.newObject[keys[keyIndex - 1]]) + " key is " + keys[keyIndex - 1]);
} else {
$("#employee-mobile-error").text("Only 10 digit number is allowed");
}
//employee landline no validataion
if (number_pattern.test($("#employee-land-line").val()) || $("#employee-land-line").val() == "") {
$("#employee-land-line-error").text("");
validElementsCount++;
main.newObject[keys[keyIndex++]] = $("#employee-land-line").val();
//alert("object is " + JSON.stringify(main.newObject[keys[keyIndex - 1]]) + " key is " + keys[keyIndex - 1]);
} else {
$("#employee-land-line-error").text("Only 10 digit number is allowed");
}
//employee website validation
if (website_pattern.test($("#employee-website").val()) || $("#employee-website").val() == "") {
$("#employee-website-error").text("");
validElementsCount++;
main.newObject[keys[keyIndex++]] = $("#employee-website").val();
} else {
$("#employee-website-error").text("Follow website pattern");
}
main.newObject[keys[keyIndex++]] = $("#employee-address").val();
if (validElementsCount == 5) {
if (value == "add") {
main.addEmployeeClick(Object.assign({}, main.newObject));
$(".employee-details-form").trigger("reset");
} else if (value == "update") {
//alert("new object is " + JSON.stringify(Object.assign({}, main.newObject), keys));
main.updateData(Object.assign({}, main.newObject), keys);
$(".employee-details-form").trigger("reset");
}
}
},
You can add .off() before #update-employee-btn click event binding in line 34.
$("#update-employee-btn").off().click(....)
Let me know if it works for you as well.

JavaScript. Check if value is not in object array

I have 2 list. One bigger and one smaller. I have added infinite scroll to keep adding items from bigger list to smaller one.
// Bigger list (data from DB)
var data;
// Smaller list
$scope.projects = [];
$scope.$watch('projectSearch', function (val) {
if (typeof val !== 'undefined' && val !== "") {
//console.log("SEARCH: " + val);
for (var a = 0; a < data.length; a++) {
if (data[a].name.toLowerCase().indexOf(val) > -1) {
console.log("FOUND: " + data[a].name);
if($scope.projects.indexOf(data[a].name) === -1) {
console.log("PUSHED " + data[a].name);
$scope.projects.push( data[a]);
} else {
console.log("ALREADY IN " + data[a].name);
}
}
}
}
});
Search form:
<input id="search" ng-model="projectSearch" placeholder="Search ..."/>
The problem is it keeps pushing items to new list. It does not check this if statement correctly
if($scope.projects.indexOf(data[a].name) === -1) {
console.log("PUSHED " + data[a].name);
$scope.projects.push( data[a]);
}
you should check for data[a], not its property name
if($scope.projects.indexOf(data[a]) === -1) {
console.log("PUSHED " + data[a].name);
$scope.projects.push( data[a]);
}
also, you could remove data[a] after copy to make next search faster
$scope.projects should be type of string assuming data[a].name is string then your indexOf function properly

what's wrong with my variable, it's undefined

my variable todoHtmlLi is undefined, really can't get it why.. I had declared it early before assign it to some html. I use console.log() to check the priority value, it work just fine..
$(document).on('click', '#addTodoBtn', function () {
var todoDialog = {
state0: {
html: dialogContent,
buttons: {
Cancel: -1,
Add: 0
},
focus: 1,
submit: function (e, v, m, f) {
e.preventDefault();
var todoHtmlLi;
var todoNameVal;
var todoNoteVal;
//Task Name
todoNameVal = $("#todoName").val();
todoNameVal.trim();
//Note
todoNoteVal = $("#todoNote").val();
todoNoteVal.trim();
//Priority
priority = $("#priority").val();
if ($(priority) === 1) {
todoHtmlLi = "<li style='background:red'><a href='#'>" + todoNameVal + "<input type='checkbox'></a></li>"
} else if ($(priority) === 2) {
todoHtmlLi = "<li style='background:green'><a href='#'>" + todoNameVal + "<input type='checkbox'></a></li>"
} else if ($(priority) === 3) {
todoHtmlLi = "<li style='background:blue'><a href='#'>" + todoNameVal + "<input type='checkbox'></a></li>"
}
if (v == 0) {
if (todoNameVal !== "") {
$("div#tab").find('#todoUl').prepend(todoHtmlLi);
$.prompt.close();
} else {
$("#todoName").focus();
}
} else {
$.prompt.close();
}
}
}
}
$.prompt(todoDialog);
});
if(v == 0){ mean the 'yes' button is clicked
First: You only assign values to todoHtmlLi based on comparing the return value of a call to val() (which will be a String) to a Number using === (which checks type).
Since "1" === 1 is not true, you never assign a value.
Either use ==, compare to Strings or convert to a Number.
Second: You pass the value as an argument to $, so you get a jQuery object back instead of that String. This doesn't make any sense, so don't do that.
if (priority == 1){
if (priority === "1"){
if (parseInt(priority,10) === 1){
Because your conditions are wrong.
see ,
priority = $("#priority").val();
That returns a string.
Then
if($(priority) === 1){
That is wrong ,Since 1 never equals to "1",So no condition satisfied.and it;s undefined.
Your if condition should be
if(priority === "1"){
And also remaining if conditions needs to be change.

Trying to add and remove items from an array

The script works by asking user for add or remove an item in the array. Then asks to continue this loop. The problem here is that my script doesn't seem to match my user's input (removeItem) to the item in the list (myList[i]). I'm at a lost as to why this is failing to match.
// new method for removing specific items from a list
Array.prototype.remove = function(from,to) {
var rest = this.slice((to || from) + 1 || this.length);
this.length = from < 0 ? this.length + from : from;
return this.push.apply(this, rest);
};
printList = function() {
var listLength = myList.length;
for (i = 0; i < listLength; i++) {
document.write(i + ":");
document.write(myList[i] + "<br/>");
};
document.write("<br/><br/>");
};
// initial list
var myList = new Array ();
if (myList.length === 0) {
document.write("I have " + myList.length + " item in my list. It is: <br/>");
}
else {
document.write("I have " + myList.length + " items in my list. They are: <br/>");
}
printList();
var continueAdding = "yes";
var askToContinue = "";
while (continueAdding === "yes") {
// loop
var askUser = prompt("What do you want to [A]dd or [R]emove an item to your inventory?").toUpperCase();
switch (askUser) {
case "A": { // add an user specified item to the list
var addItem = prompt("Add something to the list");
myList.push(addItem);
printList();
break;
}
case "R": { // remove an user specified item from the list
var removeItem = prompt("what do you want to remove?");
var listLength = myList.length;
for (i = 0; i < listLength; i++) {
if (removeItem === myList[i]) {
document.write("I found your " + removeItem + " and removed it.<br/>");
myList.remove(i);
}
else {
document.write(removeItem + " does not exist in this list.<br/>");
break;
}
if (myList.length === 0) {
myList[0] = "Nada";
}
};
printList();
break;
}
default: {
document.write("That is not a proper choice.");
}
};
askToContinue = prompt("Do you wish to continue? [Y]es or [N]o?").toUpperCase(); // ask to continue
if (askToContinue === "Y") {
continueAdding = "yes";
}
else {
continueAdding = "no";
}
}
Your loop never allows it to loop through all the items, because it breaks on the first iteration if the item doesn't match.
The break statement should be in the if block, not in the else block - use this instead:
for (i = 0; i < listLength; i++) {
if (removeItem === myList[i]) {
document.write("I found your " + removeItem + " and removed it.<br/>");
myList.remove(i);
break;
}
else {
document.write(removeItem + " does not exist in this list.<br/>");
}
};
if (myList.length === 0) {
myList[0] = "Nada";
}
Also, note that it's looking for an exact match, case sensitive, same punctuation, and everything. If you want it to be a little more lenient you'll need to modify the script to convert both strings to lowercase and strip punctuation before comparing them.
Edit: Just noticed something else -- testing for an empty list needs to be done outside the loop. I updated the above code to reflect this.

Categories