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

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;
}
}

Related

Cognitive complexity reduce issue

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

Array in Input text Field using JavaScript

I am new to JS Community and I am practicing JS. I have Input text field where User will enter the array like 1,2-5,6-9,10,12,13-15 . What I am trying is to expand this array like 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
<input class="inputC" id="inputC" type="text" value="" placeholder="Select Control" required />
JS I tried
var items = $('#inputC').val().split(",");
for (var i in items) {
console.log(items[i]);
}
Note: You should specify the logic of adding 11 in the output based on the given input.
You should split on - as well which you can do inside a map call back function.
Demo:
var items = $('#inputC').val().split(',');
items = items.flatMap(i =>{
var list = [];
i = i.split('-');
if(i.length > 1){
for (var j = i[0]; j <= i[1]; j++) {
list.push(+j);
}
}
else{
list.push(+i[0]);
}
return list;
});
console.log(items);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input class="inputC" id="inputC" value="1,2-5,6-9,10,12,13-15" type="text" value="" placeholder="Select Control" required />
let str='1,2-5,6-9,10,12,13-15';
str.split(',').map((e)=>{
if(e.includes('-')){
const values = e.split('-');
const end = parseInt(values[1]);
let start = parseInt(values[0]);
while(start < end){
console.log(start);start++;
}
}else{
console.log(parseInt(e))
}
})
This is a great scenario in which you want to create a small derived webcomponent that does just what you need:
<input is="array-input" />
class ArrayInput extends HTMLInputElement {
get value() {
let inter = super.value.split(',').map(el => el.trim());
let ret = [];
for (const el of inter) {
const [ start, end ] = el.split('-').map(Number);
if (isNaN(start)) continue;
if (!end || start > end) {
ret.push(start);
} else if (start === end) {
ret.push(start)
} else if (start < end) {
for (let i = start; i <= end; i++) {
ret.push(i);
}
}
}
return [...new Set(ret)].sort();
}
}
customElements.define('array-input', ArrayInput, {
extends: 'input'
});
<input is="array-input" onchange="console.log(this.value)" />

How to slice a part of string using typescript?

I am building up a custom select box with multi select as like angular material chips..
HTML
<div class="autocomplete">
<div class="chips-input-container">
<div class="col-md-4">
<div class="user-chip" *ngFor="let user of userSelects">
{{user.name}}
<span (click)="deleteSelects(user)" class="delete-icon-chip">✖</span>
</div>
</div>
<div class="col-md-4 form-label-group">
<input name="suggestion" type="text" id="autocomplete-input" class="form-control" placeholder="User" (click)="suggest()"
[(ngModel)]="userSelectsString" (keyup)="onKey($event)" id="autocomplete-input">
<label for="autocomplete-input" class="emailBox"></label>
<label class="fa fa-caret-down input-icon"></label>
</div>
</div>
<ul id="autocomplete-results" class="autocomplete-items" *ngIf="show">
<li *ngFor="let s of suggestions" [ngClass]="isSelected(s) ? 'selected-suggestion' : ''" (click)="selectSuggestion(s)">{{ s.name }}</li>
</ul>
</div>
TS:
import { Component } from '#angular/core';
import { FormControl } from '#angular/forms';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
suggestion: string = '';
typeahead: FormControl = new FormControl();
openSelectBox: boolean = false;
fieldHistory: string[] = [];
inputValue: string;
autocomplete_results: any;
input = document.querySelector('#autocomplete-input');
userSelectsString = '';
name = 'Angular';
userSelects = [];
suggestions = [{"id":"001","name":"mango"},{"id":"002","name":"apple"},{"id":"003","name":"banana"},{"id":"004","name":"pine"},{"id":"005","name":"orange"},{"id":"006","name":"chery"},{"id":"007","name":"watermelon"},{"id":"008","name":"grapes"},{"id":"009","name":"lemon"}];
show: boolean = false;
suggest() {
this.show = true;
}
isSelected(s:any) {
return this.userSelects.findIndex((item) => item.id === s.id) > -1 ? true : false;
}
selectSuggestion(s) {
this.userSelects.find((item) => item.id === s.id) ?
this.userSelects = this.userSelects.filter((item) => item.id !== s.id) :
this.userSelects.push(s);
this.show = false;
}
deleteSelects(s) {
this.userSelects = this.userSelects.filter((item) => item.id !== s.id);
}
assignToNgModel() {
this.userSelectsString = '';
this.userSelects.map((item) => this.userSelectsString += item.name + ' ');
}
onKey(e) {
this.inputValue = e.target.value;
if (this.inputValue.length > 0) {
var people_to_show = [];
this.autocomplete_results = document.getElementById("autocomplete-results");
this.autocomplete_results.innerHTML = '';
people_to_show = this.autocomplete(this.inputValue);
for (let i = 0; i < people_to_show.length; i++) {
this.autocomplete_results.innerHTML += '<li>' + people_to_show[i] + '</li>';
}
this.autocomplete_results.style.display = 'block';
} else {
people_to_show = [];
this.autocomplete_results.innerHTML = '';
}
}
autocomplete(val) {
var people_return = [];
for (let i = 0; i < this.suggestions.length; i++) {
if (val === this.suggestions[i].slice(0, val.length)) {
people_return.push(this.suggestions[i]);
}
}
return people_return;
}
}
As of selection and deletion part, everything works fine but when i implemented autocomplete, i am unable to get result as i am using slice for the array of objects.
My data is:
suggestions = [{"id":"001","name":"mango"},{"id":"002","name":"apple"},{"id":"003","name":"banana"},{"id":"004","name":"pine"},{"id":"005","name":"orange"},{"id":"006","name":"chery"},{"id":"007","name":"watermelon"},{"id":"008","name":"grapes"},{"id":"009","name":"lemon"}];
In the for loop, i am getting error as Property 'slice' does not exist on type '{ "id": string; "name": string; }'. in the linethis.suggestions[i].slice(0, val.length),
for (let i = 0; i < this.suggestions.length; i++) {
if (val === this.suggestions[i].slice(0, val.length)) {
people_return.push(this.suggestions[i]);
}
}
If i give any inside suggestions: any = [{"id":"001","name":"mango"},...}], it is showing slice is not a function.
Kindly help me to achieve the result of autocomplete.
Stackblitz: https://stackblitz.com/edit/angular-euuvxw
You probably want to slice the name, not the entire suggestion object. And looking at how you are using the result, you probably want to push only the name into people_return too:
for (let i = 0; i < this.suggestions.length; i++) {
if (val === this.suggestions[i].name.slice(0, val.length)) {
// ^^^^
people_return.push(this.suggestions[i].name);
}
}
You need to use slice() in array type value. In your case it is this.suggestions so use this.suggestions.slice(0, val.length)

Why does the method of adding goods work incorrectly?

When the listener "buttAdd.addEventListener" for the add method is triggered: , first this condition works several times(works with the second addition):
if (inputsAdd [0].value ===""||inputsAdd [1].value ===""||inputsAdd [2]
.value === "")
{alert ("fill all fields");}
It works when the fields are not empty, and then the product is added. And if you click on the add button with empty fields, then the product that was added earlier - will be lost. The same story awith the method, delete. Help me please to fix it
//Product Creation Class
class Product {
constructor(name, count, price) {
this.name = name;
this.count = count;
this.price = price;
}
}
Product.SORT_ORDER_ASC = 1;
Product.SORT_ORDER_DESC = -1;
// Сlass where products are recorded
class Shop {
constructor() {
this.products = [];
this.formAdd = document.forms[0];
this.inputsAdd = this.formAdd.elements;
this.buttAdd = this.formAdd.elements[3];
this.formDelete = document.forms[1];
this.nameDelete = this.formDelete.elements[0];
this.buttDelete = this.formDelete.elements[1];
}
//method for adding a product
addProduct(newProduct) {
this.products.push(newProduct);
}
//method for remove product by name
deleteProductByName(productName) {
let i = this.products.length;
while (i--) {
if (productName === this.products[i].name) {
this.products.splice(i, 1);
}
}
}
// get total price by all products
get totalProductsPrice() {
return this.products.map(product => product.price).reduce((p, c) => p + c);
}
//method for sorting the product at its price
sortProductsByPrice(sortOrder) {
const sorted = this.products.sort((a, b) => {
return a.price > b.price ? sortOrder : -sortOrder;
});
this.products = sorted;
}
// method to draw the table with product property (
// name, count, price)
show() {
// add new product by click
this.buttAdd.addEventListener('click', (e) => {
e.preventDefault();
if (this.inputsAdd[0].value === "" || this.inputsAdd[1].value === "" || this.inputsAdd[2].value === "") {
alert("fill all fields");
} else {
this.addProduct(new Product(this.inputsAdd[0].value, parseInt(this.inputsAdd[2].value),
parseInt(this.inputsAdd[1].value)));
this.show();
this.inputsAdd[0].value = "";
this.inputsAdd[1].value = "";
this.inputsAdd[2].value = "";
}
}, false);
// delete product by name after click
this.buttDelete.addEventListener('click', (e) => {
e.preventDefault();
if (this.nameDelete.value === "") {
alert("write a name of product what you want to delete");
} else {
this.deleteProductByName(this.nameDelete.value);
this.show();
this.nameDelete.value = "";
}
}, false);
const rows = document.querySelectorAll("#shop .data");
for (let i = rows.length - 1; i >= 0; i--) {
const e = rows.item(i);
e.parentNode.removeChild(e);
}
const table = document.getElementById("shop");
const tFoot = table.querySelector('tfoot');
if (tFoot) tFoot.remove();
for (let i = 0; i < this.products.length; i++) {
//create table
table.innerHTML += `<tbody><tr class="data"><td>${this.products[i].name}</td>
<td>${this.products[i].price}</td>
<td>${this.products[i].count}</td></tr></tbody>`;
}
//show total price by all products
table.innerHTML += `<tfoot><tr><td colspan="3" id="total-price">Total price:
${this.totalProductsPrice}</td></tr></tfoot>`;
//filter products by price
document.addEventListener("click", (e) => {
let elem = e.target;
if (elem.id === "filter") {
this.sortProductsByPrice(Product.SORT_ORDER_ASC);
this.show();
}
}, false);
console.log(this.products);
}
}
let shop = new Shop();
shop.addProduct(new Product("product", 1, 2000));
shop.addProduct(new Product("product1", 2, 500));
shop.addProduct(new Product("product2", 3, 1000));
shop.show();
<div class="Shop">
<div class="add-product">
<h1>Add product</h1>
<form id="addForm">
<label for="name" >Name of product</label>
<input type="text" id="name" class="input-product">
<label for="price">Price of product</label>
<input type="text" id="price" class="input-product">
<label for="count">Count of product</label>
<input type="text" id="count" class="input-product">
<button id="add" type="button">Add</button><!-- *** -->
</form>
</div>
<div class="product-table">
<h2>Products</h2>
<form id="delete-form">
<label for="name-delete">Delete product by name</label>
<input type="text" id="name-delete" class="input-delete">
<button id="delete" type="button">Delete</button>
</form>
<table id="shop">
<caption>Products that are available in the store</caption>
<tr>
<th>Name:</th>
<th id="filter">Price:</th>
<th>Count:</th>
</tr>
</table>
</div>
</div>
See, you're defining let shop = new Shop() and then use this variable in your Shop class, like shop.show(). I strongly recommend you to use this keyword instead of scoped variable (valid for all other shop usage entries).
Now, about
works several times
I assume, that when you call the show() method it registers more event listeners some time. I mean, you call show - it creates new event listeners + sometimes calls itself (huh, it is pretty risky). I suggest you to move listeners declaration to the constructor - so they will be instantinated once (but that will require keeping DOM nodes). Also it would be nice to split your show fucntion to several smaller functions and get rid of self function emit (it will reduce complexity).

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.

Categories