Cognitive complexity reduce issue - javascript

i made a login system with JavaScript for a game idea i had, but apparently my ide says it is too complex, do i need to split one function in more pieces? Do it reduces computer processing time? I just don't know if it's critical or not.
Anyway this is the code:
class Log {
constructor() {
this.list = {
username: ["admin", "helper"],
password: ["admin", "h24"]
};
this.user = document.getElementById('username');
this.psw = document.getElementById('password');
this.posUser = null;
this.posPsw = null;
this.t = true;
}
login() {
if (this.user.value != '' && this.user.value != null) {
if (!this.list.username.includes(this.user.value.toLowerCase())) {
errors.innerHTML = 'This user does not exist.';
} else {
for (let i = 0; i < this.list.username.length; i++) { //user[pos]
let j = this.user.value.toLowerCase();
if (j === this.list.username[i]) {
this.posUser = i;
}
}
for (let k = 0; k < this.list.password.length; k++) { //psw[pos]
let l = this.psw.value;
if (l === this.list.password[k]) {
this.posPsw = k;
}
}
if (this.posUser === this.posPsw) {
//access
console.log('access');
} else { // user[pos] != psw[pos] then show error
errors.innerHTML = 'Incorrect password.';
}
}
}
}
}
let errors = document.querySelector('.error');
let invite = new Log();
document.querySelector('.btnLog').addEventListener('click', function() {
invite.login();
});
* {
margin: 5px;
}
<div class="form">
<div class="inline">
<label>user</label><input type="text" id="username" autocomplete="off" />
</div>
<div class="inline">
<label>psw</label><input type="password" id="password" autocomplete="off" />
<div class="eye"></div>
</div>
<div class="flex-start">
<button class="btn btnLog">login</button>
</div>
<div class="inline none -error">
<div class="err_img"></div>
<div class="error"></div>
</div>
</div>

If your IDE uses Sonar to compute the cognitive complexity i suggest you to break up your code in multiple method calls
read this blog post to find out more https://blog.sonarsource.com/cognitive-complexity-because-testability-understandability

Related

need to append user data to array

my original question got answered but I realize that every time I try to push user data in the arrays it wouldn't allow me to do is there any another to append data to arrays or is the push method the only way. or should i create a new array................................................................
"use strict"
const names = ["Ben", "Joel", "Judy", "Anne"];
const scores = [88, 98, 77, 88];
const $ = selector => document.querySelector(selector);
const addScore = () => {
// get user entries
const name = $("#name").value;
const score = parseInt($("#score").value);
let isValid = true;
// check entries for validity
if (name == "") {
$("#name").nextElementSibling.textContent = "This field is required.";
isValid = false;
} else {
$("#name").nextElementSibling.textContent = "";
}
if (isNaN(score) || score < 0 || score > 100) {
$("#score").nextElementSibling.textContent = "You must enter a valid score.";
isValid = false;
} else {
$("#score").nextElementSibling.textContent = "";
}
if (isValid) {
names.push("#name");
scores.push("#score");
names[names.length] = name;
scores[scores.length] = score;
$("#name").value = "";
$("#score").value = "";
}
$("#name").focus();
};
// display scores
const displayScores = () => {
for (let i = 0; i < names.length; i++) {
document.getElementById("scores_display").textContent += names[i] + " = " +
scores[i] +
"\n";
}
};
document.addEventListener("DOMContentLoaded", () => {
$("#add").addEventListener("click", addScore);
$("#display_scores").addEventListener("click", displayScores())
$("#name").focus();
});
<main>
<h1>Use a Test Score array</h1>
<div>
<label for="name">Name:</label>
<input type="text" id="name">
<span></span>
</div>
<div>
<label for="score">Score:</label>
<input type="text" id="score">
<span></span>
</div>
<div>
<label> </label>
<input type="button" id="add" value="Add to Array">
<input type="button" id="display_scores" value="Display Scores">
</div>
<div>
<textarea id="scores_display"></textarea>
</div>
</main>
All my previous notes were incorrect. Your adhoc $ const threw me off! My apologies.
The issue was you weren't calling displayScores() after updating the array. Plus, I added a line to that function to clear the existing text before looping through your data.
"use strict"
const names = ["Ben", "Joel", "Judy", "Anne"];
const scores = [88, 98, 77, 88];
const $ = selector => document.querySelector(selector);
const addScore = () => {
// get user entries
const name = $("#name").value;
const score = parseInt($("#score").value);
let isValid = true;
// check entries for validity
if (name == "") {
$("#name").nextElementSibling.textContent = "This field is required.";
isValid = false;
} else {
$("#name").nextElementSibling.textContent = "";
}
if (isNaN(score) || score < 0 || score > 100) {
$("#score").nextElementSibling.textContent = "You must enter a valid score.";
isValid = false;
} else {
$("#score").nextElementSibling.textContent = "";
}
if (isValid) {
names.push("#name");
scores.push("#score");
names[names.length] = name;
scores[scores.length] = score;
$("#name").value = "";
$("#score").value = "";
// add to the textarea
displayScores()
}
$("#name").focus();
};
// display scores
const displayScores = () => {
document.getElementById("scores_display").textContent = "";
for (let i = 0; i < names.length; i++) {
document.getElementById("scores_display").textContent += names[i] + " = " +
scores[i] +
"\n";
}
};
document.addEventListener("DOMContentLoaded", () => {
$("#add").addEventListener("click", addScore);
$("#display_scores").addEventListener("click", displayScores())
$("#name").focus();
});
<main>
<h1>Use a Test Score array</h1>
<div>
<label for="name">Name:</label>
<input type="text" id="name">
<span></span>
</div>
<div>
<label for="score">Score:</label>
<input type="text" id="score">
<span></span>
</div>
<div>
<label> </label>
<input type="button" id="add" value="Add to Array">
<input type="button" id="display_scores" value="Display Scores">
</div>
<div>
<textarea rows="6" id="scores_display"></textarea>
</div>
</main>

Unable to add the item in array on scan in Angular 2

I am developing an application using Angular 2.. In my application I am using barcode scanner to scan in the text field and storing those items in the array.
When I scan the item get added to array, but when I scan another item the old item it replace the old value in array.
Below is the piece of code which I am using. Please help me if you see any fix for the weird issue.
import { Component,ViewChild,Input, Output,OnInit,ChangeDetectorRef } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { HeaderComponent } from '../common/header.component';
//import { SaleCart } from '../model/SaleCart';
//import * as $ from "jquery";
declare var jQuery: any
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./posapp.component.css']
})
export class TestComponent implements OnInit{
title = 'Treewalker POS';
public cartItems = [];
public query;
public filteredList = [];
public products = [{"id":"3","name":"Pears Soap Original 75gm","sku":"89675432189","price":"32.00","special_price":"32.00","qty":null,"barcode":"89675432189","tax":"5","discount":"0"},{"id":"1","name":"Rin","sku":"1111111111111","price":"11.00","special_price":"11.00","qty":"10.000","barcode":"1111111111111","tax":"5","discount":"0"},{"id":"2","name":"Test 1","sku":"23456","price":"10.00","special_price":"10.00","qty":"10.000","barcode":"23456","tax":"5","discount":"0"}];
constructor() {
}
ngOnInit() {
}
add(item) {
/* check the items in the json data */
let flag = false;
var foodItem = {};
for (let product of this.products) {
if(product.barcode == item) {
flag = true;
foodItem['ctr'] = 1;
foodItem['item'] = product;
break;
}
}
let localCart = [];
if(sessionStorage.getItem("cart")){
localCart = JSON.parse(sessionStorage.getItem("cart"));
//console.log(JSON.stringify(localCart));
}
//console.log("food "+JSON.stringify(this.cart));
if(flag && localCart.length) {
let exist = 0;
for(let i=0; i < localCart.length; i++) {
if(localCart[i].item.barcode == item) {
localCart[i].ctr = parseInt(localCart[i].ctr) + 1;
//console.log("#### "+this.cart[i].ctr+" --- "+item);
exist = 1;
}
}
if(!exist){
localCart.push(foodItem);
}
sessionStorage.setItem("cart",JSON.stringify(localCart));
//this.barcode = "";
}else if(flag){
localCart.push(foodItem);
sessionStorage.setItem("cart",JSON.stringify(localCart));
}
//this.cart = JSON.parse(sessionStorage.getItem("cart"));
//this.itemsCnt = localCart.length;
//console.log("--- "+this.itemsCnt);
console.log(JSON.parse(sessionStorage.getItem('cart')));
//this.onScanProduct.emit(localCart);
}
filter(e) {
//e.preventDefault();
if (this.query !== ""){
this.filteredList = this.products.filter(function(el){
if(el.barcode.toLowerCase() == this.query.toLowerCase()) {
return el.barcode.toLowerCase() == this.query.toLowerCase();
}else{
return el.barcode.toLowerCase().indexOf(this.query.toLowerCase()) > -1;
}
}.bind(this));
/* scanned item will be added to the cart */
console.log(this.filteredList.length);
if(this.filteredList.length > 0 && e.which == 13){
//console.log(JSON.stringify(this.filteredList));
for (let product of this.filteredList) {
//console.log(filter.barcode+"=="+this.query);
if(product.barcode == this.query) {
this.add(product.barcode);
jQuery('#barcode').val("");jQuery('#barcode').focus();
this.filteredList = [];
}
}
}
}else{
this.filteredList = [];
}
}
}
Below is the html template
<div class="content-wrapper">
<section class="content">
<form>
<div class="row">
<!-- sales item add window -->
<!-- end -->
<div class="col-sm-4">
<div class="box box-primary">
<div class="box-body">
<div class="form-group">
<div class="row">
<div class="col-md-9">
<!--<input type="text" class="form-control" id="barcode" name="barcode" [(ngModel)]="barcode" (ngModelChange)="add($event)"
placeholder="Enter item code or scan the barcode" autocomplete="off" />-->
<input id="barcode" type="text" class="form-control validate filter-input" name="query" [(ngModel)]="query" (keyup)="filter($event)" placeholder="Enter item code or scan the barcode" autocomplete="off" [ngModelOptions]="{standalone: true}">
</div>
<div class="suggestions" *ngIf="filteredList.length > 0">
<ul>
<li *ngFor="let item of filteredList" >
<a (click)="select(item)" href="javascript:;">{{item.barcode}} {{item.name}}</a>
</li>
</ul>
</div>
<div class="col-md-3">
<button type="button" class="btn btn-primary" (click)="createnewproduct(newproduct)">New Product</button>
</div>
</div>
</div>
</div> <!-- end of box body -->
</div>
</div>
</div><!-- end of row -->
</form>
</section>
</div>
Below is the input field which is being used to scan the barcode
<input id="barcode" type="text" class="form-control validate filter-input" [(ngModel)]="query" (keyup)="filter()" placeholder="Enter item code or scan the barcode" autocomplete="off">
I am assuming you are using only the function add. I tried to implement in a javascript like in the following code but I am pretty sure you are referencing that object somewhere else and you are changing it. That's my conclusion but I might be wrong.
var factoryP = (function(){
function P() {
this.cart = [];
this.products = [{'barcode': 1, 'name': 'a'}, {'barcode': 1, 'name': 'b'}]
}
function add(item) {
/* check the items in the json data */
//console.log("cart length "+JSON.stringify(this.cart));
let flag = false;
var foodItem = {};
for (let product of this.products) {
if(product.barcode == item) {
//console.log("check "+item);
flag = true;
foodItem['ctr'] = 1;
foodItem['item'] = product;
break;
}
}
if(flag && this.cart.length) {
let exist = 0;
for(let i=0; i < this.cart.length; i++) {
if(this.cart[i].item.barcode == item) {
//console.log("Same product");
this.cart[i].ctr = parseInt(this.cart[i].ctr) + 1;
exist = 1;
}
}
if(!exist){
console.log(foodItem);
this.cart.push(foodItem);
}
}else if(flag){
console.log("step 4 "+item);
this.cart.push(foodItem);
}
}
P.prototype.add = add;
return new P();
});
instanceP = factoryP();
instanceP.add(1);
instanceP.add(1);
instanceP.add(1);
instanceP.add(2);
console.log(instanceP.cart[0].ctr)
//output 3
instanceP.cart[1].ctr
//output 1
Check your code here. Every time you are initializing the foodItem array with empty array. So whenever code will call add method, it will first empty your foodItem array.
Please check my comment in your code below:
add(item) {
let flag = false;
//Akshay: You need to make your changes here. Initialize your foodItem array out of this scope
var foodItem = {};
for (let product of this.products) {
if(product.barcode == item) {
//console.log("check "+item);
flag = true;
foodItem['ctr'] = 1;
foodItem['item'] = product;
break;
}
}

Difficulty with error "Uncaught TypeError: Cannot read property 'name' of undefined"

I've been working on a JavaScript code in order to make a checkout cart of a pizza, but have been having an issue with the showCart function.
let pizzas=[
{ name:"Pepperoni", img:"pizza.png", price:8.99},
{ name:"Alfredo", img:"pizza.png", price:9.99},
{ name:"Cheese", img:"cheese.png", price:7.99}
];
function registerButtonEvents()
{
let buttons=document.getElementsByTagName("button");
for(let i = 0; i < buttons.length-1; i++)
{
buttons[i].addEventListener("click", function() {
addToCart(i);
});
}
let number = localStorage.getItem("number");
if(number == null)
number = 0;
document.getElementById("num").innerHTML = number;
}
function addToCart(pId)
{
let cartJ = localStorage.getItem("cart");
let cart;
if(cartJ===null) //Cart is empty
{
cart=[];
}
else
{
cart=cartJ.split(",");
}
cart.push(pId);
let number= localStorage.getItem("number");
if(number===null)
number = 0;
document.getElementById("num").innerHTML = `${++number}`;
localStorage.setItem("cart", cart.toString());
localStorage.setItem("number", number);
}
function clearCart()
{
localStorage.removeItem("cart");
localStorage.removeItem("num");
}
function showCart()
{
let cartJ = localStorage.getItem("cart");
let cart = [];
let info = "";
if(cartJ === null)
{
document.getElementById("myCart").innerHTML=`<h2>No items in cart!</h2>`;
}
else
{
cart = cartJ.split(",");
for (let i in cart)
{
let item = pizzas[cart[i]];
info+=
`<div class="row">
<div class="col-md-2 text-center">
<h3>${item.name}</h3>
</div>
<div class="col-md-2 text-center">
<img class="pizza" src="./images/${item.img}" alt="pepperoni">
</div>
<div class="col-md-2 text-center">
<h3>${item.price}</h3>
</div>
<div class="col-md-2 text-center">
<button type="button" class="btn btn-primary" onclick="removePizza(${i})">Remove</button>
</div>
</div>
`;
}
document.getElementById("myCart").innerHTML=info;
}
}
function removePizza(piz)
{
var cart = localStorage.getItem("cart");
cart = cart.split(",");
cart.splice(piz, 1);
if (cart.length == 0)
clearCart();
else
{
localStorage.setItem("cart", cart);
localStorage.setItem("number",cart.length);
}
showCart();
}
Developer tools tell me that the error is in the line in:
let item = pizzas[cart[i]];
but I don't necessarily understand why. If anyone could send some feedback it would be greatly appreciated.
The problem is when you access <h3>${item.name}</h3>. Your item is undefined there because your cart (cart = cartJ.split(",");) probably stores some strings like "Pepperoni" (as you split them using a comma) and after that you want to access the pizzas array using one of those strings instead of an index.

Javascript Product Search (working, but need to filter by search term)

I have a little product search code that I've been working on for a while. It works great, although a bit backwards.
The more keywords I type in, ideally, the less products will show up (because it narrows down the results). But as is stands, the more keywords I type in my search system, the MORE products are displayed, because it looks for any product with any of the keywords.
I want to change the script so that it only shows results if they include ALL the searched for keywords, not ANY of them...
Sorry for the long-winded explanation.
Here's the meat and potatoes (jsfiddle):
http://jsfiddle.net/yk0Lhneg/
HTML:
<input type="text" id="edit_search" onkeyup="find_my_div();">
<input type="button" onClick="find_my_div();" value="Find">
<div id="product_0" class="name" style="display:none">Mac
<br/>Apple
<br/>
<br/>
</div>
<div id="product_1" class="name" style="display:none">PC
<br/>Windows
<br/>
<br/>
</div>
<div id="product_2" class="name" style="display:none">Hybrid
<br/>Mac PC Apple Windows
<br/>
<br/>
</div>
JAVASCRIPT:
function gid(a_id) {
return document.getElementById(a_id);
}
function close_all() {
for (i = 0; i < 999; i++) {
var o = gid("product_" + i);
if (o) {
o.style.display = "none";
}
}
}
function find_my_div() {
close_all();
var o_edit = gid("edit_search");
var str_needle = edit_search.value;
str_needle = str_needle.toUpperCase();
var searchStrings = str_needle.split(/\W/);
for (var i = 0, len = searchStrings.length; i < len; i++) {
var currentSearch = searchStrings[i].toUpperCase();
if (currentSearch !== "") {
nameDivs = document.getElementsByClassName("name");
for (var j = 0, divsLen = nameDivs.length; j < divsLen; j++) {
if (nameDivs[j].textContent.toUpperCase().indexOf(currentSearch) !== -1) {
nameDivs[j].style.display = "block";
}
}
}
}
}
So, when you search "mac pc" the only result that should be displayed is the hybrid, because it has both of those keywords. Not all 3 products.
Thank you in advance!
I changed a little bit your code to adjust it better to my solution. I hope you don't mind. You loop first over the terms, and then through the list of products, I do it the other way around.
How this solution works:
Traverse the list of products, for each product:
Create a counter and set it to 0.
Traverse the list of search terms, for each.
If the word is found in the product's name, add 1 to the counter.
If the counter has the same value as the list length, display the product (matched all words)
function gid(a_id) {
return document.getElementById(a_id);
}
function close_all() {
for (i = 0; i < 999; i++) {
var o = gid("product_" + i);
if (o) {
o.style.display = "none";
}
}
}
function find_my_div() {
close_all();
var o_edit = gid("edit_search");
var str_needle = edit_search.value;
str_needle = str_needle.toUpperCase();
var searchStrings = str_needle.split(/\W/);
// I moved this loop outside
var nameDivs = document.getElementsByClassName("name");
for (var j = 0, divsLen = nameDivs.length; j < divsLen; j++) {
// set a counter to zero
var num = 0;
// I moved this loop inside
for (var i = 0, len = searchStrings.length; i < len; i++) {
var currentSearch = searchStrings[i].toUpperCase();
// only run the search if the text input is not empty (to avoid a blank)
if (str_needle !== "") {
// if the term is found, add 1 to the counter
if (nameDivs[j].textContent.toUpperCase().indexOf(currentSearch) !== -1) {
num++;
}
// display only if all the terms where found
if (num == searchStrings.length) {
nameDivs[j].style.display = "block";
}
}
}
}
}
<input type="text" id="edit_search" onkeyup="find_my_div();">
<input type="button" onClick="find_my_div();" value="Find">
<div id="product_0" class="name" style="display:none">Mac
<br/>Apple
<br/>
<br/>
</div>
<div id="product_1" class="name" style="display:none">PC
<br/>Windows
<br/>
<br/>
</div>
<div id="product_2" class="name" style="display:none">Hybrid
<br/>Mac PC Apple Windows
<br/>
<br/>
</div>
You can also see it on this version of your JSFiddle: http://jsfiddle.net/yk0Lhneg/1/

What's wrong in this JavaScript code?

I can't figure it out..
Markup:
<form>
<fieldset><p>
<label>Username: <input type="text" name="user" id="user" /></label></p><br /><p>
<label>Password: <input type="password" name="passw" id ="passw" /></label></p>
<label><input type="submit" value="Log in" name="submitBUT" style="width: 65px; height: 25px; background-color: green; color: white; font-weight: bold;" id="submitBUT" /><div id="helllo"></div></label>
</fieldset>
</form>
Code:
var subBut = document.getElementById('submitBUT');
var users = ['hithere', 'Peter112', 'Geksj', 'lOsja', 'fInduS', '323DssaAA', 'f1fsus'];
var passes = ['mllesl', 'Petboy', 'Heneeesh', 'Olga', '234dasdf77/', 'minls', 'ew832ja'];
var output = [];
function submi(u, p) {
for (var i = 0; i < users.length; i++) {
if (users[i] == u) {
output.push(i);
}
}
for (var o = 0; o < output.length; o++) {
if (passes[output[o]] == p) {
return p + ' was a correct password.';
}
}
return 'Error, please try again';
}
subBut.onclick = (document.getElementById('helllo').innerHTML=(submi(document.getElementById('user').value, document.getElementById('passw').value)));
LIVE CODE; http://jsfiddle.net/w87MS/
and yes, I know you don't store passwords in the source code :D, it's just "fur t3h lulz"
I have to agree with comments above, not sure what you're doing but...the problem is that a submit handler is a function not the string you're assigning, this:
subBut.onclick = (document.getElementById('helllo').innerHTML=(submi(document.getElementById('user').value, document.getElementById('passw').value)));
should be:
subBut.onclick = function() {
document.getElementById('helllo').innerHTML=
submi(document.getElementById('user').value, document.getElementById('passw').value);
return false; //for testing, prevent form submission
};
You can test the updated version here.

Categories