array.push() repeats same value - javascript

This is an object I tried to create to manage a list, but somethings wrong somewhere, whenever I used the list.addItem(); for the second or third time, all the values(array) in the list.list; changes to the finally added value(array).
var list = {
list : [],
eligible: function(item){
var status = true;
var dw = (item.w*item.h*item.l)/169;
if(dw > item.m){
status = true;
}else{
status = false;
}
return status;
},
addItem : function(item){
if(this.eligible(item)){
this.list.push(item);
console.log(this.list);
this.refresh();
alertify.success('Item Added to List');
}else{
alertify.warning('Item not eligible for Freight Calculation');
}
},
removeItem : function(item){
if(this.inList(item)){
var itemIndex = this.list.indexOf(item);
if(itemIndex > -1){
this.list.splice(itemIndex,1);
alertify.success('Item Removed from List');
this.refresh();
}
}else{
alertify.error('Item NOT in List');
}
},
inList: function(item){
var bool = false;
if (this.list.filter(function(e) { return e.id === item.id; }).length > 0) {
bool = true;
}else{
bool = false;
}
return bool;
},
findItem: function (id) {
for (var i = 0; i < this.list.length; i++) {
if (this.list[i].id === id) {
return this.list[i];
}
}
},
refresh: function(){
if(this.list.length > 0){
$('.items .table tbody').empty();
var itemNo = 0;
$.each( this.list, function( key, item ) {
$('.items .table tbody').append('</tr><tr><td>' + ++itemNo + '</td><td>' + item.qty + '</td><td>' + item.m + '</td><td>' + item.h + '</td><td>' + item.w + '</td><td>' + item.l + '</td><td><button data-item=\"' + item.id + '\" class=\"btn btn-remove btn-block\"><i class=\"far fa-minus-square\"></i></button></td><td>Price</td></tr>')
});
}else{
$('.items .table tbody').html('<tr><td colspan=\"8\" style=\"text-align:center;\"> No Items Added.</td></tr>')
}
}
};
I can't find whats wrong, maybe it's because I've been trying this all day. Btw I'm new to programming.
UPDATE: This is how i call the addItem:
var id=0; //just for reference
$('.btn-add-item').click(function(){
var item = [];
item.id = ++id;
item.qty = parseInt($('input[name=qty]').val());
item.m = parseFloat($('input[name=weight]').val()).toFixed(3);
item.w = parseFloat($('input[name=width]').val()).toFixed(2);
item.h = parseFloat($('input[name=height]').val()).toFixed(2);
item.l = parseFloat($('input[name=length]').val()).toFixed(2);
item.country = $('#countrySelect').val();
list.addItem(item);
});

In your click handler you are assigning each input element's value to the variable item as if item were an Object. Unfortunately, you've initialized item as an Array. You should initialize item as an Object. Then, your list Array will contain a list of Objects.
Change
var item = [];
To
var item = {};
Since you are new to programming, and Javascript is sort special in an odd way with this code, please let me explain why there was no error thrown to let you know this.
In JavaScript, Arrays are actually Objects. So assigning a value like you have (item.blah) actually places that property on the item Array Object as a property, but doesn't know your intent is to add the value to the list of Array elements. Javascript carries out what it believes is your intent.

Related

Loop through Array of Objects and append the Object to an Array if it doesn't exist

Desired Functionality: On selecting a checkbox, a span is created with an id & data attribute same as the checkbox and appended to a div. On clicking the 'x' on this span should uncheck the checkbox and remove the span as well.
Issue: On selecting the checkbox, an additional span with an 'undefined' label is created.
JSFIDDLE
var filtersApplied = [];
$('.ps-sidebar').on('change', 'input[type=checkbox]', function () {
var me = $(this);
console.log('me', me);
if (me.prop('checked') === true) {
filtersApplied.push([
...filtersApplied,
{ id: me.attr('id'), data: me.attr('data-filter-label') }
]);
} else {
filtersApplied = filtersApplied.map(function (item, index) {
return item.filter(function (i) {
return i.id !== item[index].id;
});
});
}
if (filtersApplied.length === 0) {
$('.ps-plans__filters').hide();
$('.ps-plans__filters-applied').html('');
} else {
$('.ps-plans__filters').show();
var filtersAppliedHtml = '';
filtersApplied.map(function (elements) {
console.log('items', elements);
return elements.map(function (el, i) {
console.log('item', el);
return (filtersAppliedHtml +=
'<span class="ps-plans__filter" id="' + el.id + '_' + i +'">' +el.data +
'<span class="icon-remove-circle remove-filter" data-filter="' +el.data +'"> X</span></span>');
});
});
console.log('filtersAppliedHtml', filtersAppliedHtml);
console.log($('.ps-plans__filters-applied').html(filtersAppliedHtml));
}
});
Your undefined label is because of the ...filtersApplied
if (me.prop('checked') === true) {
filtersApplied.push([
//this ...filtersApplied
{ id: me.attr('id'), data: me.attr('data-filter-label') }
]);
Note that filtersApplied is an array and you're making a push(), this method inserts a value in the end of the array, so your ...filtersApplied makes no sense. Just remove it and you'll be fine. You can se more here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push
there are few thing that need to be fixed.
when adding an element you should not push filtersApplied along with new object. instead you better do arr = [...arr, obj];
when remove an item you could apply a filter instead based on me.attr('id'). with map you would get undefined values;
after that you would map only once to build your html content, not twice;
var filtersApplied = [];
$('.ps-sidebar').on('change', 'input[type=checkbox]', function () {
var me = $(this);
if (me.prop('checked') === true) {
filtersApplied = [
...filtersApplied,
{ id: me.attr('id'), data: me.attr('data-filter-label') }
];
} else {
filtersApplied = filtersApplied.filter(function (item, index) {
return me.attr('id') !== item.id;
});
}
if (filtersApplied.length === 0) {
$('.ps-plans__filters').hide();
$('.ps-plans__filters-applied').html('');
} else {
$('.ps-plans__filters').show();
var filtersAppliedHtml = '';
filtersApplied.map(function (el, i) {
return (filtersAppliedHtml +=
'<span class="ps-plans__filter" id="' +
el.id +
'_' +
i +
'">' +
el.data +
'<span class="icon-remove-circle remove-filter" data-filter="' +
el.data +
'"> X</span></span>');
});
$('.ps-plans__filters-applied').html(filtersAppliedHtml);
}
});

String array with key and value Remove already exist

I found some similar questions, but none helped me.
I have an array, and I am pushing items into it. I want to check if there is already an item then removes and add a new value.
I am doing this in the success of an ajax call,
var taxSplitUp = []; // my array
// ajax call here, in the success
for (var i in data.d) {
var ItemTaxAmt= data.d[i].ItemTaxAmt;
var TaxName = data.d[i].TaxName;
var idx = $.inArray(TaxName, taxSplitUp); // checks if already exist
if (idx == -1) {
var tx1 = '{"' + TaxName + '":"' + parseFloat(ItemTaxAmt).toFixed(2) + '"}';
taxSplitUp.push(tx1);
}
else {
taxSplitUp.splice(idx, 1); // removing
var t1 = taxSplitUp[TaxName]; // selecting the value from array
var tx1 = '{"' + TaxName + '":"' + parseFloat(ItemTaxAmt).toFixed(2) + parseFloat(t1).toFixed(2) + '"}';
taxSplitUp.push(tx1);
}
}
Here if the same key came, then I want to add the values together and want only one in the array, but the checking always returns false and adds another into the array.
please help.
$.inArray wont work with associative array. Try below solution
for (var i in data) {
var ItemTaxAmt= data[i].ItemTaxAmt;
var TaxName = data[i].TaxName;
console.log(TaxName);
$.map(taxSplitUp, function(item, index) {
if (item.TaxName == TaxName) {
item.ItemTaxAmt = ItemTaxAmt;
}else{
taxSplitUp.push({
'TaxName' :TaxName,
'ItemTaxAmt' : ItemTaxAmt
});
}
});
}
console.log(taxSplitUp);

show and hide element options for my case

I'm having a little bit of difficulties when I need to hide an element on a page.
I am using this script to create my multiselect dropdown element which is the main controller for the elements on the page (http://wenzhixin.net.cn/p/multiple-select/docs/#the-basics1).
It returns an array of selected elements and my elements have their showIfValues set in a JSON file.
My functions should do this:
I get selected values from the dropdown element in array (ex. ["value1", "value2"]).
Going through all the elements and find where in showIfValue is any value from the array above, show it
In the change of the multiselect dropdown, if any of the fields are removed, remove the element but leave the rest on the page.
Legend in showHideHendler function:
inp is the id of the input field I would like to show on the page
controlInp is the control input (in this case multiselect dropdown)
value is the array populated with the showIfValues from JSON file of the elements
So far I made it here. These are the things I have implemented.
function diffArray(arr1, arr2) {
return arr1.concat(arr2).filter(function (val) {
if (!(arr1.includes(val) && arr2.includes(val)))
return val;
});
}
function getSelectedValues(controlInput){
if($('#' + controlInput).attr("multiple") === "multiple"){
// var selectValues = $('#' + controlInput).multipleSelect("getSelects");
var selectValues = [];
if($('#' + controlInput).multipleSelect("getSelects") != null) {
selectValues = $('#' + controlInput).multipleSelect("getSelects");
}
return selectValues;
}
}
var multipleShowHideHandler = (function() {
var selectedValues = [];
function setSelectedValues(value){
selectedValues.push(value);
}
function overrideSelected(value){
selectedValues = value;
}
function getSelectedValues(){
return selectedValues;
}
return {
setSelectedValues: setSelectedValues,
getSelectedValues: getSelectedValues,
overrideSelected: overrideSelected
}
})();
function showHideHandler(inp, controlInp, value) {
if (!$('#' + controlInp).is(':checkbox') && !($.isArray(value))) {
value = $.makeArray(value);
}
var selectedValues = getSelectedValues(controlInp);
if(($('#' + controlInp).attr("multiple") === "multiple") && !$.isEmptyObject(selectedValues)){
$('#' + controlInp).change(function(){
var oldState = multipleShowHideHandler.getSelectedValues();
var selectedValues = getSelectedValues(controlInp);
if($.isEmptyObject(oldState)){
$.each(selectedValues, function(i, val){
multipleShowHideHandler.setSelectedValues(val);
});
}
var differentArray = diffArray(selectedValues, oldState);
if(!$.isEmptyObject(differentArray)){
if(($.inArray(differentArray[0], value) !== -1)){
$('#' + inp + 'Container').hide();
}
multipleShowHideHandler.overrideSelected(selectedValues);
}
//check diff
/*if(!$.isEmptyObject(selectedValues) && !$.isEmptyObject(oldState)){
var diff = diffArray(selectedValues, oldState);
}*/
$.each(selectedValues, function(i, val){
if(($.inArray(val, value) !== -1)){
$('#' + inp + 'Container').show();
}
});
});
}else if (($.inArray($('#' + controlInp).val(), value) > -1) || $('#' + controlInp).prop('checked') === value) {
$('#' + inp + 'Container').show();
} else {
$('#' + inp + 'Container').hide();
}
}
This works on some elements, but the moment it overrides my oldState the fields are not hidden.
Any kind of help is much appreciated. Thanks in advance.
After looking and trying many things, I have found that the easiest way is basically to remove all elements and show them again on any change of the multiple select dropdown element.
So the final code looks like this:
if(($('#' + controlInp).attr("multiple") === "multiple") && !$.isEmptyObject(selectedValues)){
$('#' + controlInp).change(function(){
var selectedValues = getSelectedValues(controlInp);
if(!$.isEmptyObject(selectedValues)){
$('#' + inp + 'Container').hide();
$.each(selectedValues, function(i, val){
if(($.inArray(val, value) !== -1)){
$('#' + inp + 'Container').show();
}
});
}else{
$('#' + inp + 'Container').hide();
}
});
}
There is no need to add a before state and after so this is the only thing I need.
DiffArray and multipleShowHideHandler are no longer needed.
Hope this helps someone in the future.

How can I delete Items from json string without using $.grep

I have a cart variable and I am storing the cart inside it like this.
[{"course_id":"24","doc_id":"211","doc_title":"PDF Notes","doc_price":"500"},{"course_id":"25","doc_id":"217","doc_title":"PDF Notes","doc_price":"500"},{"course_id":"25","doc_id":"218","doc_title":"PDF Solved Past Papers","doc_price":"500"},{"course_id":"26","doc_id":"224","doc_title":"PDF Solved Past Papers","doc_price":"595"}]
I created a RemoveFromCart function. It works in simple JQUERY But it is not working in Framework 7 because of $.grep. Is there any other way I can do it without using $.grep?
This is my Function
function removeFromCart(course_id, doc_id) {
var x = confirm("Are you sure you want to remove this item from your cart?");
if (x) {
$$('#cart_body').html('');
existing_cart = localStorage.getItem("cart");
if (existing_cart == '') {
existing_cart = [];
} else {
existing_cart = JSON.parse(existing_cart);
}
existing_cart = $.grep(existing_cart, function (data, index) {
return data.doc_id != doc_id
});
ex_cart = JSON.stringify(existing_cart);
localStorage.setItem('cart', ex_cart);
existing_cart = localStorage.getItem("cart");
if (existing_cart == '') {
existing_cart = [];
} else {
existing_cart = JSON.parse(existing_cart);
}
if (existing_cart !== null && existing_cart.length > 0) {
var total = '';
$$('#cart_div').show();
existing_cart.forEach(function (arrayItem) {
var text = '';
text = '<li class="item-content"><div class="item-inner"><div class="item-title">' + arrayItem.doc_title + '</div><div class="item-after">' + arrayItem.course_id + '</div><div class="item-after">' + arrayItem.doc_price + '</div><div class="item-after"><i class="icon icon-cross" onclick="removeFromCart(' + arrayItem.course_id + ',' + arrayItem.doc_id + ')"></i></div></div></li>';
total = Number(total) + Number(arrayItem.doc_price);
$$('#cart_body').append(text);
});
text = '<tr><td></td><td class="text-center"><b>Total: </b></td><td class="text-center">' + total + '</td><td></td></tr>';
$$('#cart_body').append(text);
} else {
$$('#cart_div').hide();
text = '<p>Your cart is empty.</p>';
$$('#cart_body').append(text);
}
} else {
return false;
}
}
Instead of:
$.grep(existing_cart, function ...
You can use:
existing_cart.filter(function ...
var new_courses = existing_cart.map( v=> {
if(v.doc_id != doc_id)
return v
}).filter( v=> {return v})
// new_courses does not contain the course with doc_id
map loops through each member of an array. filter removes members not returned in map.

Custom JQuery dynamic link creation

I'm pretty new to js and having a hard time figuring out the best way to generate a custom url depending on what links are selected. You can view what I have done here. http://jsfiddle.net/1fz50z1y/26/ I will also paste my info here.
var products = [];
var quantity = [];
qstring = '';
$('input.product-radio, select.products-howmany').change(function() {
var $this = $(this)
var $product = $(this).closest('.product-options-left');
var $radio = $product.find('input.product-radio');
var $select = $product.find('select.products-howmany')
var qid = $select.val();
var pid = $radio.val();
currentStatus = $radio.prop('checked'),
theString = '';
qString = '';
pString = '';
if (currentStatus) {
products.push(pid);
quantity.push(qid);
if ($product.find('div.quantity').removeClass('q-hidden')) {
//code
}
} else {
products.splice(products.indexOf(pid), 1);
quantity.splice(quantity.indexOf(qid), 1);
$product.find('div.quantity').addClass('q-hidden');
}
if ((products.length > -1) || (quantity.length > -1)) {
if ((products.length === 0) || (quantity.length === 0)) {
console.log("Q Length: " + quantity.length);
pString += products[0];
qString += quantity[0];
console.log("qString = " + quantity);
} else {
pString = products.join('-p');
qString = quantity.join('_q');
if (quantity.length > 1) {
qString = quantity.splice(quantity.indexOf(qid), 1);
pString = products.splice(products.indexOf(pid), 1);
}
console.log("+ Q Length: " + quantity.length);
console.log("ADDING " + "p" + pString + "_q" + qString);
}
if ((qString == 'undefined') || (pString == 'undefined')) {
$('a.options-cart').prop("href", "#");
} else {
//$('a.options-cart').prop("href", "/cart/add/p" + theString + "_q" + qstring + "?destination=/cart");
//$('a.options-cart').prop("href", "/cart/add/p" + theString + "?destination=/cart");
$('a.options-cart').prop("href", "/cart/add/p" + pString + "_q" + qString + "?destination=/cart");
}
}
});
$('a.options-cart').click(function() {
alert(qstring);
var $this = $(this);
href = $this.attr('href');
if (href == '#') {
alert("You must select a product.");
return false;
}
});
When you click on the add link icon it displays a drop down where you can select the quantity. So changing the quantity should also update the link and how it is created. I am trying to figure out how to create the link so the end result looks like so.
cart/add/p123_q1?destination=/cart this is how it would look with a single item. Where p = the product ID and q = the quantity. Unclicking the add to cart should remove those items and changing the drop down should update the quantity. If there is more than one item it should append to the link like so. cart/add/p123_q1-p234_q2-p232_q4?destination=/cart and then unclicking or changing quantity on any of those items should reflect the change in the link. I am not sure if I am going about this all wrong but I have been trying forever and many different routes to go about trying to achieve this effect. If anyone could please help me figure this out I would be greatly appreciated!
I was able to get this to work properly using this piece of code. Hope this maybe helps someone.
$('input.product-radio, select.products-howmany').change(function () {
var $product = $(this).closest('.product-options-left');
var $radio = $product.find('input.product-radio');
var $select = $product.find('select.products-howmany')
$product.find('div.quantity').toggleClass('q-hidden', !$radio.prop('checked'));
$product.find('label.quantity').toggleClass('q-hidden', !$radio.prop('checked'));
var string = $('.product-radio')
.filter(':checked')
.map(function(){
return $(this)
.closest('.product-options-left')
.find('.products-howmany')
.val();
})
.get()
.join('-');
$('a.options-cart').prop("href", "/cart/add/" + string + "?destination=/cart");
});
$('a.options-cart').click(function() {
alert(qstring);
var $this = $(this);
href = $this.attr('href');
if (href == '#') {
alert("You must select a product.");
return false;
}
});

Categories

Resources