infinite algorithm. javascript - javascript

i'm pretty new to js. i'm sorry if this sounds dumb.I have such an algorithm for javascript. when executed, it loops. Why? What is his mistake?
I have such source data
enter image description here
let incomesArray = [];
incomesArray[0] = {
income_id: incomeList[0].id,
worker_id: incomeList[0].worker_id,
worker_surname: incomeList[0].worker_surname,
worker_name: incomeList[0].worker_name,
incomeList: [
{
provider_name: incomeList[0].provider_name,
product_category: incomeList[0].product_category_name,
product_name: incomeList[0].product_name,
product_count: incomeList[0].product_count,
purchase_price: incomeList[0].purchase_price
}
],
incomeDate: incomeList[0].date,
total: incomeList[0].total
}
if(incomesArray.length > 0 ){
for(let i = 1; i < incomeList.length; i++) {
for(let j = 0; j < incomesArray.length; j++){
if(incomeList[i].id == incomesArray[j].id){
for(let k = 0; k < incomesArray[j].incomeList.length; k++){
incomesArray[j].incomeList.push({
provider_name: incomeList[i].provider_name,
product_category:
incomeList[i].product_category_name,
product_name: incomeList[i].product_name,
product_count: incomeList[i].product_count,
purchase_price: incomeList[i].purchase_price
})
}
} else if (incomesArray[j].id !== incomeList[i].id) {
incomesArray.push({
income_id: incomeList[i].id,
worker_id: incomeList[i].worker_id,
worker_surname: incomeList[i].worker_surname,
worker_name: incomeList[i].worker_name,
incomeList: [
{
provider_name: incomeList[i].provider_name,
product_category: incomeList[i].product_category_name,
product_name: incomeList[i].product_name,
product_count: incomeList[i].product_count,
purchase_price: incomeList[i].purchase_price
}
],
incomeDate: incomeList[i].date,
total: incomeList[i].total
})
}
}
}
}
I will be grateful for any help or hint.

It's your else part that causes the problem. For every item in incomesArray that has a different id than the item in incomeList you add another entry to incomesArray; while you're iterating over that array. Like this gif:
Extending the track while you're driving on it.
Second, your comparison: if(incomeList[i].id == incomesArray[j].id) but incomesArray[j] has no id, only a income_id, so you'll always run into the else part where you add more items to incomesArray.
I've restructured your code a bit:
const incomesArray = [];
for (const row of incomeList) {
let target = incomesArray.find(item => item.income_id === row.id);
if (!target) {
incomesArray.push(target = {
income_id: row.id,
worker_id: row.worker_id,
worker_surname: row.worker_surname,
worker_name: row.worker_name,
incomeList: [],
incomeDate: row.date,
total: row.total
});
}
target.incomeList.push({
provider_name: row.provider_name,
product_category: row.product_category_name,
product_name: row.product_name,
product_count: row.product_count,
purchase_price: row.purchase_price
});
}

Related

Add or remove a value from a localstorage object

I want add or remove 1 by click for one of the obj.onlist in this array from localstorage
{loklakchicken: {name: "Lok Lak Chicken", tag: "loklakchicken", price: 9.9, onList: 2},…}
Lottchabeef: {name: "Lot Tcha Beef", tag: "Lottchabeef", price: 9.9, onList: 1}
loklakchicken: {name: "Lok Lak Chicken", tag: "loklakchicken", price: 9.9, onList: 2}
loklakvegan: {name: "Lok Lak Vegan", tag: "loklakvegan", price: 9.9, onList: 17}
lottchavegan: {name: "Lot Tcha Vegan", tag: "lottchavegan", price: 9.9, onList: 2}
I try something like this
let obj = localStorage.getItem('prodOnList');
obj = JSON.parse(orderListItems);
for (let i = 0; i < obj.length; i++) {
$('.plus').click(function () {
obj[i].onList += 1;
}
$('.minus').click(function () {
obj[i].onList -= 1;
}
}
localStorage.setItem("prodOnList", JSON.stringify(obj));
I am sure i am missing something pretty obvious, thx
UPDATE
I am doing a cart list create with JS and for each product on the list I have a button to add or remove one...
I try to bind my function setItems on btn plus click event no result...
My problem is i dont now how to target the object from the array on localstorage where i am calling the event click!
thx for your help
class OrderBtn{
constructor(){
this.prodList = [
just remove the array with the products
];
}
addToList(){
let menus = document.querySelectorAll('.add-list');
for (let i = 0; i < menus.length; i++) {
$(menus[i]).click(()=>{
this.listCount(this.prodList[i]);
this.totalPrice(this.prodList[i]);
this.displayOrderList();
});
}
}
listCount(prod){
let productNum = localStorage.getItem('listNum');
productNum = parseInt(productNum);
if (productNum) {
localStorage.setItem('listNum', productNum + 1);
} else {
localStorage.setItem('listNum', 1);
}
this.setItems(prod);
}
setItems(prod){
let orderListItems = localStorage.getItem('prodOnList');
orderListItems = JSON.parse(orderListItems);
if (orderListItems !== null){
if(orderListItems[prod.tag] === undefined){
orderListItems = {
...orderListItems,
[prod.tag]: prod
}
}
orderListItems[prod.tag].onList += 1;
} else{
prod.onList = 1;
orderListItems = {
[prod.tag]: prod
}
}
localStorage.setItem("prodOnList", JSON.stringify(orderListItems));
}
totalPrice(prod){
let orderTotal = localStorage.getItem('totalCost');
if(orderTotal !== null){
orderTotal = parseFloat(orderTotal);
let resultPrice = orderTotal + prod.price;
resultPrice = resultPrice.toFixed(2);
localStorage.setItem('totalCost', resultPrice);
} else {
localStorage.setItem('totalCost', prod.price.toFixed(2));
}
}
displayOrderList(){
let orderItems = localStorage.getItem('prodOnList');
let orderTotal = localStorage.getItem('totalCost');
orderItems = JSON.parse(orderItems);
let orderContainer = document.querySelector('.orderList');
if (orderItems && orderContainer) {
orderContainer.innerHTML = "";
Object.values(orderItems).map(item =>{
let totalItem = item.onList * item.price;
totalItem = totalItem.toFixed(2);
orderContainer.innerHTML += `
<div class="quantity d-flex justify-content-between align-items-center mb-2">
<i class="fas fa-times text-danger"></i>
<div class="itemNum">
<i class="btnMinus fas fa-minus"></i>
<span class="mx-2">${item.onList}</span>
<i class="btnPlus fas fa-plus"></i>
</div>
<span class="total">${totalItem} €</span>
</div>
<div class="product d-flex justify-content-between align-items-center">
<span>${item.name}</span>
</div>
`;
});
$('.totalOrder').text(`Total : ${orderTotal} €`)
}else{
orderContainer.innerHTML = `
<p class="product">Votre panier est vide</p>`;
$('.totalOrder').text(`Total : 0.00 €`)
}
}
}
If I didn't misunderstood your problem, this will work for you
$('.plus').click(function () {
addOrRemoveByOne('add');
}
$('.minus').click(function () {
addOrRemoveByOne('remove');
}
addOrRemoveByOne(option) {
let obj = JSON.parse(localStorage.getItem('prodOnList'));
for (let key in obj) {
if (option === 'add') {
obj[key].onList += 1;
}
if (option === 'remove') {
obj[key].onList -= 1;
}
}
localStorage.setItem("prodOnList", JSON.stringify(obj));}
}

Append text by matching object array's attribute and element id's digit

I have a list of object array with id and value as its properties. Basically what I want is, the num.items[i].value should go in each div as pair. One: one and so on.
If num.items[i].id doesn't have the digit (like the array doesn't include id 3) then the id="digit_3" should be left blank.
HTML
<ul>
<li>One: <div id="digit_1">s</div></li>
<li>Two: <div id="digit_2">sd</div></li>
<li>Three: <div id="digit_3">sdf</div></li>
<li>Four: <div id="digit_4">sdf</div></li>
</ul>
Javascript
var num = {
items: [
{ id:4, value:"four"},
{ id:1, value:"one"},
{ id:2, value:"two"},
]
};
for(var i=0; i<num.items.length; i++){
document.getElementById("digit_"+i+1).innerHTML = i+1;
console.log(i+1)
}
Required output
One: one
Two: two
Three:
Four: four
I know we cannot compare the id digit but any modification in HTML is greatly appreciated.
it's really simple - you just have to understand arrays and objects:
var num = {
items: [{
id: 4,
value: "four"
},
{
id: 1,
value: "one"
},
{
id: 2,
value: "two"
},
]
};
var cleanableElements = document.querySelectorAll("ul li div");
for (var i = 0; i < cleanableElements.length; i++) {
cleanableElements[i].innerHTML = '';
}
var index;
for (var i = 0; i < num.items.length; i++) {
index = num.items[i].id;
document.getElementById("digit_" + index).innerHTML = num.items[i].value;
}
<ul>
<li>One:
<div id="digit_1"></div>
</li>
<li>Two:
<div id="digit_2"></div>
</li>
<li>Three:
<div id="digit_3"></div>
</li>
<li>Four:
<div id="digit_4"></div>
</li>
</ul>
Best idea would be to select all elements with querySelectorAll and setting empty before next step. You can't really detect all #digit_X id's so you can't just check for unchanged DIVs as you can't reliably detect them all.
You should loop ul li div then check id whether is in num.items.
Assuming your id format is digit_*.
var num = {
items: [
{ id:4, value:"four"},
{ id:1, value:"one"},
{ id:2, value:"two"},
]
}
function checkItems(num){
items = document.querySelectorAll('#target_div li div')
indexes = num.items.reduce( (pre, cur) => {
pre[cur.id] = cur.value
return pre
}, {}) // loop num.items then create one dict with key=id.
items.forEach(function(item){ //loop ul li div, then check whether id in dict=indexes.
let ids = item.id.split('_')
if(ids[1] in indexes){
item.innerHTML += ' #Found:'+item.id
} else {
item.innerHTML = ''
}
})
}
checkItems(num)
<ul id="target_div">
<li>One: <div id="digit_1">s</div></li>
<li>Two: <div id="digit_2">sd</div></li>
<li>Three: <div id="digit_3">sdf</div></li>
<li>Four: <div id="digit_4">sdf</div></li>
</ul>
I know I did something awkward but if div have already some value then above example will not work expect #sphinx answer I guess
var num = {
items: [{
id: 4,
value: "four"
},
{
id: 1,
value: "one"
},
{
id: 2,
value: "two"
},
]
};
var idsArray = [];
var valuesArray = [];
for (var value of num.items) {
idsArray.push(value.id);
valuesArray.push(value.value);
}
var maxId = Math.max(...idsArray);
for (var i = 1; i <= maxId; i++) {
if (idsArray.indexOf(i) !== -1) {
document.getElementById("digit_" + i).innerHTML = valuesArray[idsArray.indexOf(i)];
} else {
document.getElementById("digit_" + i).innerHTML = "";
}
}
div {
display: inline
}
<ul>
<li>One: <div id="digit_1">s</div></li>
<li>Two: <div id="digit_2">sd</div></li>
<li>Three: <div id="digit_3">sdf</div></li>
<li>Four: <div id="digit_4">sdf</div></li>
</ul>

display alternate image in an array by checking existing another array whether the element is present or not in angular2?

I have two arrays like this
arr1[]= [{name:"aaa",id:"23"},{name:"aaa",id:"24"},{name:"aaa",id:"25"},{name:"aaa",id:"26"}];
arr2[]=[{name:"aaa",id:"23"},{name:"aaa",id:"24"},{name:"aaa",id:"25"}];
I want to display a.jpg for elements of matched between arrays
and b.jpg images for unmatched elements. How do I proceed this in angular2?
for(var i=0; i< this.ticketlists.length; i++ )
{
for(var j=0; j<this.favlist.length; j++)
{
if(this.ticketlists[i].id == this.favlist[j].id)
{
this.ticketlists[i].starimgsass = "assets/images/star_icon.png";
console.log("matched id",this.ticketlists[i].id);
}
else
{
this.ticketlists[i].starimgsass = "assets/images/star_icon1.png";
console.log("unmached id",this.ticketlists[i].id);
}
}
}
<ul class="listboxtickets">
<li class="selectlistticket" *ngFor="let tick of ticketlists">
<div class="atickid"> {{tick.id}} </div>
<div class="atickname"> {{tick.summary.substring(0,20)}} </div>
<div class="atickstat"> <img class="staraimg" [src]="tick.starimgsass" (click)="changeassigntofav(tick.id)"/> </div>
<div class="namelinet"> <img src="assets/images/text_bottomline.png"/> </div>
</li>
this is not work well
for(var i=0; i< this.ticketlists.length; i++ )
{
for(var j=0; j<this.favlist.length; j++)
{
if(this.ticketlists[i].id == this.favlist[j].req_id)
{
this.ticketlists[i].starimgsass = "assets/images/star_icon1.png";
console.log("matched id",this.ticketlists[i].id);
}
}
}
// this.ticketlists = [];
for(var i=0; i< this.ticketlists.length; i++ )
{
if(this.ticketlists[i].starimgsass == null)
{
this.ticketlists[i].starimgsass = "assets/images/star_icon.png";
}
}
This works ultimately fine
You can do something like this:
#Component({
selector: 'my-app',
template: `
<img [attr.src]="source(i)" *ngFor="let x of arr1; let i = index;">
`,
})
export class App {
arr1= [0,1,2,3,4];
arr2=[0,1,3];
source(i) {
const inBoth = this.arr1.some(a => i === a) && this.arr2.some(a => i === a);
return inBoth ? 'a.jpg' : 'b.jpg'
}
}
Plunker

Making calculations from nested arrays in AngularJS

I have the following array:
$scope.products = [
{
nom : "Pa de fajol",
img : "dill1.jpg",
descripcio: [
"Pa de motlle"
],
preu:4.90,
tipus: "Pa"
},
{
nom : "Pagès semi integral de blat/espelta",
img : "dill2.jpg",
descripcio: [
"Pa de pagès",
"680g / 400g"
],
tipus: "Pa",
variacions : [
{
nom: "Gran",
preu: "3.70",
grams: "680g",
basket: 0
},
{
nom: "Petit",
preu: "2.30",
grams: "400g",
basket: 1
}
]
}
In the frontend I display it with an ng-repeat and depending if the product has price (preu) or not, I display one input for quantity for single product, or one input for each variation.
Looks like this:
<div ng-repeat="pa in products">
<div ng-if="!pa.preu" ng-repeat="vari in pa.variacions">
<input type="number" ng-model="pa.variacions.basket" ng-init="pa.variacions.basket=0">
</div>
<input ng-if="pa.preu" type="number" ng-model="pa.basket" name="basket" ng-init="pa.basket=0">
</div>
<a ng-click="insert()">Add to cart</a>
When I trigger insert(), I have a function that will add the products and calculate the total price, but so far it only works for products with a price, not for the variations.
The function looks like this:
$scope.insert = function() {
$scope.singleorder = [];
for(var i = 0; i < $scope.products.length; i++)
if($scope.products[i].basket) { // if input has been setted
$scope.singleorder.push({
'product': $scope.products[i].nom,
'number': $scope.products[i].basket,
'preu': ($scope.products[i].preu * $scope.products[i].basket)
});
}
console.log($scope.singleorder);
}
How would I have to proceed to include in the $scope.singleorder array also the calculations from the nested array of variations?
Any tips?
EDIT
See Plunkr to reproduce the issue
SOLUTION
I managed to fix it with the help of some comments!
See Plunkr for final version.
Here's the final function:
$scope.insert = function() {
$scope.singleorder = [];
for(var i = 0; i < $scope.products.length; i++)
if($scope.products[i].basket) { // if input has been setted
$scope.singleorder.push({
'product': $scope.products[i].nom,
'number': $scope.products[i].basket,
'preu': ($scope.products[i].preu * $scope.products[i].basket)
});
}
else if($scope.products[i].variacions) { // if input has been setted
angular.forEach($scope.products[i].variacions, function(variacions) {
if(variacions.basket) {
$scope.variname = $scope.products[i].nom + ' (' + variacions.nom + ')'
$scope.singleorder.push({
'product': $scope.variname,
'number': variacions.basket,
'preu': (variacions.preu * variacions.basket)
});
}
});
}
console.log($scope.singleorder);
Your issue was that your variacions is an array use this,
$scope.insert = function() {
$scope.singleorder = [];
for(var i = 0; i < $scope.products.length; i++)
if($scope.products[i].basket) { // if input has been setted
$scope.singleorder.push({
'product': $scope.products[i].nom,
'number': $scope.products[i].basket,
'preu': ($scope.products[i].preu * $scope.products[i].basket)
});
}
else if($scope.products[i].variacions) { // if input has been setted
for(var j=0;j<$scope.products[i].variacions.length; j++){
$scope.singleorder.push({
'product': $scope.products[i].variacions[j].nom,
'number': $scope.products[i].variacions[j].basket,
'preu': ($scope.products[i].variacions[j].preu * $scope.products[i].variacions[j].basket)
});
}
}
console.log($scope.singleorder);
}
See Plunkr

Angular JS: Multiple Data Bindings Into Table

Okay. I'm pulling together a data table that is going to look through majors and minors of a school. I'm running into issues of trying not to repeat myself in the data where every possible, but am not sure how to get the data pulled into the document, or even how to setup the data into the different arrays. Looking for some advice and help in whichever of these two areas I can find. When I search through docs and API's none of them seem to go deep enough into the data to really get what I'm looking to accomplish.
I have made a plunker to showcase my problem more clearly, or at least I hope to make it clearer.
http://plnkr.co/edit/2pDmQKKwjO6KVullgMm5?p=preview
EDIT:
It would even be okay with me if the degree each degree could be read as a boolean, and same with Education level. I'm just not sure how to go about it without repeating the whole line in a new table row. http://www.clemson.edu/majors
HERE IS THE HTML
<body ng-app="app">
<h2> Majors and Minors </h2>
<table ng-controller="MajorsCtrl">
<tbody>
<tr>
<th>Department</th>
<th>Major</th>
<th>Education Level</th>
<th>Location </th>
<th>Degree</th>
<th>Department Website </th>
</tr>
<tr ng-repeat="major in majors">
<td>{{major.Department}}</td>
<td>{{major.Major}}</td>
<td>{{major.EdLevel}}</td>
<td>{{major.Type}}</td>
<td>{{major.Degree}}</td>
<td>{{major.Website}}</td>
</tr>
</tbody>
</table>
</body>
HERE IS THE JS
var app = angular.module('app', []);
// Majors and Minors Data That will be injected into Tables
app.controller('MajorsCtrl', function($scope) {
// Heres where it gets tricky
// Now I have biology with four diff degree types
// Biology with 2 diff EdLevels
// How do I combine all of these into 1 Group without repeating
var majorsInfo = [
{
Department:'Statistics',
Major:'Applied Statitistics',
EdLevel:'Graduate',
Type:'Campus/Online',
Degree:'Graduate Certificate',
Website: 'http://biology.wvu.edu',
},
{
Department:'Biology',
Major:'Biology',
EdLevel:'Graduate',
Type:'Campus',
Degree:'PH.D' ,
Website: 'http://biology.wvu.edu',
},
{
Department:'Biology',
Major:'Biology',
EdLevel:'Graduate',
Type:'Campus',
Degree:'M.S' ,
Website: 'http://biology.wvu.edu',
},
{
Department:'Biology',
Major:'Biology',
EdLevel:'Undergraduate',
Type:'Campus',
Degree:'B.A.' ,
Website: 'http://biology.wvu.edu',
},
{
Department:'Biology',
Major:'Biology',
EdLevel:'Undergraduate',
Type:'Campus',
Degree:'B.S.' ,
Website: 'http://biology.wvu.edu',
},
];
$scope.majors = majorsInfo;
});
This seems to be a question about modeling the data. I took a few assumptions:
A department can offer multiple majors
A department has a website
Each major can offer one to many Educations (i.e. Education Level, On/Off Campus, Degree)
The department can offer multiple minors with the same data structure as majors
I modeled a set of "enums" and Programs/Departments after your data. I used enums for ease of updating the values in multiple locations:
app.factory("EducationEnums", function () {
var EdLevels = {
GRAD: "Graduate",
UGRAD: "Undergraduate"
};
var Types = {
CAMPUS: "Campus",
ONLINE: "Online",
HYBRID: "Campus/Online"
};
var Degrees = {
PHD: "PH.D",
MS: "M.S.",
BS: "B.S.",
BA: "B.A.",
GCERT: "Graduate Certificate"
};
return {
EdLevels: EdLevels,
Types: Types,
Degrees: Degrees
}
});
app.factory("Programs", function (EducationEnums) {
var EdLevels = EducationEnums.EdLevels;
var Types = EducationEnums.Types;
var Degrees = EducationEnums.Degrees;
return [
{
Department: "Biology",
Website: "http://biology.wvu.edu",
//Majors offered by department
Majors: [{
Major: "Biology",
Education: [
{
EdLevel: EdLevels.GRAD,
Type: Types.CAMPUS,
Degree: Degrees.PHD
},
{
EdLevel: EdLevels.GRAD,
Type: Types.CAMPUS,
Degree: Degrees.MS
},
{
EdLevel: EdLevels.UGRAD,
Type: Types.CAMPUS,
Degree: Degrees.BA
},
{
EdLevel: EdLevels.UGRAD,
Type: Types.CAMPUS,
Degree: Degrees.BS
}
]
}],
Minors: [{
//Minors can go here
}]
},
{
Department: "Statistics",
Website: "http://biology.wvu.edu",
Majors: [{
Major: "Applied Statistics",
Education: [
{
EdLevel: EdLevels.GRAD,
Type: Types.HYBRID,
Degree: Degrees.GCERT
},
{
EdLevel: EdLevels.UGRAD,
Type: Types.CAMPUS,
Degree: Degrees.BS
}
]
}],
Minors: [{
//Minors can go here
}]
}
]
});
Next, I made a Majors service that uses this Programs data to build ViewModels (to be bound to scope in the controllers). Here you can build your original table, or you can build a matrix (like the Clemson site):
app.service("Majors", function (Programs, EducationEnums) {
var Degrees = this.Degrees = EducationEnums.Degrees;
//Build ViewModel for all details
this.getMajorDetails = function () {
var arr = [];
var programLen;
var majorLen;
var eduLen;
for (var i = 0; i < (programLen = Programs.length); ++i) {
var p = Programs[i];
var dept = p.Department;
var ws = p.Website;
var Majors = p.Majors;
for (var j = 0 ; j < (majorLen = Majors.length); ++j) {
var maj = Majors[j].Major;
var edu = Majors[j].Education;
for (var k = 0; k < (eduLen = edu.length); ++k) {
arr.push({
Department: dept,
Major: maj,
EdLevel: edu[k].EdLevel,
Type: edu[k].Type,
Degree: edu[k].Degree,
Website: ws
});
}
}
}
return arr;
}
//Build ViewModel for Degrees offered (similar to Clemson)
this.getMajorMatrix = function () {
var arr = [];
var programLen;
var majorLen;
var eduLen;
for (var i = 0; i < (programLen = Programs.length); ++i) {
var p = Programs[i];
var Majors = p.Majors;
for (var j = 0; j < (majorLen = Majors.length); ++j) {
var maj = Majors[j].Major;
var edu = Majors[j].Education;
var obj = {
Major: maj
};
for (var k = 0; k < (eduLen = edu.length); ++k) {
var degree = edu[k].Degree;
if (degree === Degrees.PHD) {
obj.PHD = true;
}
else if (degree === Degrees.MS) {
obj.MS = true;
}
else if (degree === Degrees.BS) {
obj.BS = true;
}
else if (degree === Degrees.BA) {
obj.BA = true;
}
}
arr.push(obj);
}
}
return arr;
}
});
Your controller can just call the Majors service methods to bind the ViewModel to the $scope:
app.controller('MajorsCtrl', function($scope, Majors) {
$scope.majorDetails = Majors.getMajorDetails();
});
app.controller("MajorMatrixCtrl", function ($scope, Majors) {
$scope.Degrees = Majors.Degrees;
$scope.majorMatrix = Majors.getMajorMatrix();
});
Separting like this would allow you to later update the Programs factory to not just use static data, but could pull from a service via $http for instance. The Programs data can be manipulated to achieve your desired ViewModel through the Majors service (and Minors service if you choose to write a separate one).
Updated Plunkr

Categories

Resources