I was writing code for shopping cart function. When ever I add a product to cart, for each product, at first time and additional attribute called quantity gets added.
This is my code:
myStoreCartService.factory('Cart',function() {
var userCart = [];
var cartSummary = [];
var cartConsolidatedData = [];
var currentTotalMaster;
function formCart() {
cartConsolidatedData = [];
var dup = false;
var temp;
for(x in userCart) {
dup = false;
for(z in cartConsolidatedData) {
if(cartConsolidatedData[z].productname == userCart[x].productname) {
cartConsolidatedData[z].quantity = cartConsolidatedData[z].quantity + 1;
dup = true;
break;
}
}
if(!dup) {
// temp = userCart[x];
// temp.quantity = 1;
cartConsolidatedData.push(userCart[x]);
for(y in cartConsolidatedData) {
if(cartConsolidatedData[y].productname == userCart[x].productname) {
cartConsolidatedData[y].quantity = 1;
break;
}
}
}
}
};
return {
addItemToCart: function(cartData) {
console.log(cartData);
userCart.push(cartData);
formCart();
},
retrieveCart: function() {
return userCart;
}
});
Here even the fist item in userCart variable get quantity attribute, however just cartConsolidatedData variable's values should have got the this attribute.
I am stuck bad time here.
I'm not sure I understand your code but I suppose cartData is an object and you push that object to userCart like this
userCart.push(cartData);
then you push the same object to cartConsolidatedData with this command
cartConsolidatedData.push(userCart[x]);
So when you do this:
cartConsolidatedData[y].quantity=1;
You are adding a property to the cartData object and not as you state to the cartConsolidatedData array. Because cartConsolidatedData[y] is a cartData object and since it's a reference it means any change you do to it will also be reflected in the userCart array that points to the same cartData.
Related
Can someone explain me this strange js behavior ?
All of this is in AngularJS.
I have helper function in my main app.js to simply return element from an array by its id:
var MyLib = MyLib || {};
MyLib.helpers = {
find: function(needle, stack) {
for (var i = 0; i < stack.length; i++) {
if(stack[i]._id === needle)
return stack[i];
}
return false;
}
}
Then I have factory and function to handle database change:
// categories are grabbed from db
var categories = [some array of objects];
// change is object returned from database that has all info about object as well as new object itself
function handleChange(change) {
var _category = MyLib.helpers.find(change.id, categories);
// if deleted, that part is ok
if(change.deleted) {
var idx = categories.indexOf(_category);
if(idx !== -1) {
categories.splice(idx, 1);
}
} else {
// if updated that part is weird
if(_category) {
_category = change.doc;
}
// if newly added that part is ok
else {
categories.push( angular.copy(change.doc) );
}
}
}
Why when I try to update element grabbed from categories array doesn't update in categories array ?
// categories ARE NOT updated after this
_category = change.doc;
and only when I refer to categories by index like this:
// categories ARE updated after this although _category is returned from this array by index (find function)
var idx = categories.indexOf(_category);
categories[idx] = change.doc;
I don't understand this...
You are overwriting the variable with a new value and any reference to prior value is gone.
Instead of overwriting the original object value with a new object you could update the existing object using angular.extend()
angular.extend(_category, change.doc);
I didn't analyze everything, but you should always have dot notation.
_category pass by value, and will not change when 'MyLib.hel ...' is changed
var _category = MyLib.helpers.find(change.id, categories);
something.category pass by reference, and will be changed when 'MyLib.hel ...' is changed
var something.category = MyLib.helpers.find(change.id, categories);
I'm facing an weird issue here every time I am pushing obj to the array arrays length is increasing as expected but the object which I am push at last that is overriding all other object, I am not able to identify my mistake so please help me. Thanks in Advance please check following code.
var tablehead = {};
var experimentsData = [];
var obj = {};
var remoteSheet = response.result.values;
remoteSheet.filter(function(innerArrayItem) {
if (i == 0) {
tablehead = innerArrayItem;
i++;
} else {
$.each(tablehead, function(key, value) {
obj[value] = innerArrayItem[key];
});
experimentsData.push(obj);
}
});
Because you're pushing the same object everytime. obj is only created once and at each iteration you override data you put in it at the previous iteration.
var experimentsData = [];
// var obj = {}; <-- don't define obj here
var remoteSheet = response.result.values;
remoteSheet.filter(function(innerArrayItem) {
if (i == 0) {
tablehead = innerArrayItem;
i++;
} else {
var obj = {} // <-- define it here
$.each(tablehead, function(key, value) {
obj[value] = innerArrayItem[key];
});
experimentsData.push(obj);
}
});
Also, filter is a bad way of iterating an array, I recommend switching to a basic for loop.
I have a function like this :
$scope.saveSearch = function () {
var alreadyExist = false;
for (var i = 0; i < $scope.savedSearch.length; i++) {
if (JSON.stringify($scope.searched) === JSON.stringify($scope.savedSearch[i])) {
alreadyExist = true;
break;
}
}
if (!alreadyExist) {
$scope.savedSearch.push($scope.searched);
localStorage.setItem("savedSearch", JSON.stringify($scope.savedSearch));
}
};
Before that : $scope.savedSearch = [];
$scope.searched = {
IS: "",
area: "",
block: "",
type: "",
level: ""
};
The values in $scope.searched object are initialized and then modified by the user.
My problem is :
$scope.savedSearch always contains only the last pushed object. Instead of adding the object to the array, it just replaces the current object.
I don't understand why.
You'll want to change your push line to:
$scope.savedSearch.push(angular.copy($scope.searched));
I believe your problem is that objects are passed by reference. Since the object you have in the savedSearch is always pointing to the exact object you're searching, alreadyExist will always be true.
My guess is that the object reference is being stored in your array, not the actual object itself. Because of this, any subsequent calls to push the object to your array will not work because the object reference already exists in the array. It's merely updated.
Try this instead. Use angular.copy() to create a deep copy of the object and push the copy to your array. See if that works.
if (!alreadyExist) {
$scope.savedSearch.push(angular.copy($scope.searched));
localStorage.setItem("savedSearch", JSON.stringify($scope.savedSearch));
}
You are pushing the Object outside of the for so only 1 element get pushed in try move it inside the for and every object which doesnt already exist will be pushed in
$scope.saveSearch = function () {
var alreadyExist = false;
for (var i = 0; i < $scope.savedSearch.length; i++) {
if (JSON.stringify($scope.searched) === JSON.stringify($scope.savedSearch[i])) {
alreadyExist = true;
break;
}
if (!alreadyExist) {
$scope.savedSearch.push($scope.searched);
localStorage.setItem("savedSearch", JSON.stringify($scope.savedSearch));
}
}
};
easier way would be to just
$scope.saveSearch = function () {
var alreadyExist = false;
for (var i = 0; i < $scope.savedSearch.length; i++) {
if (JSON.stringify($scope.searched) != JSON.stringify($scope.savedSearch[i])) {
$scope.savedSearch.push($scope.searched);
localStorage.setItem("savedSearch", JSON.stringify($scope.savedSearch));
}else{
break
}
}
};
Background
I have a plain JS array, initially empty. I later populate it with values. The values sent to it are numbers that are Knockout observables. Later, I want to compare those values to values in another, knockout observable array. My problem is that whenever I pass the index of the current item in my array loop, and pass that index value (a number!), the array returns a function. To get an idea, look at the JS that follows.
Note that my project and actual script is viewable on JSBin. Further, to view the problem in the console, you have to add assignments, then press 'sort'.
JSBin: http://jsbin.com/fehoq/177/edit]1
JS
//example script that follows actual script
var _this = this;
//initialize my array
this. lowest = [];
// I want to compare values in lowest to values in this array
this.scores = ko.observableArray();
// method that does comparison
this.myMethod = function(){
// initialize my helper, k
var k;
...
// loop through one array
ko.utils.arrayForEach(_this.scores(), function (score) {
// make sure my value is a number...
if (!isNaN(parseFloat(score()))) {
// this is important, I need to current index for comparison
k = _this.scores.indexOf(score);
console.log(k);
// this is where things break - it prints a function, not a value!
console.log(_this.lowest[k]);
// useless check, the value is a function, so they're always different
if (score()!=_this.lowest[k]){
// do stuff
}
}
}
}
Update
Putting the method I'm using, maybe someone will notice something I missed given that my syntax is correct(?).
this.mean = (function(scores,i) {
var m = 0;
var count = 0;
var k;
ko.utils.arrayForEach(_this.scores(), function(score) {
console.log([typeof score(), score()]);
if (!isNaN(parseFloat(score()))) {
console.log(i);
console.log(_this.lowest[i]);
if (score() != _this.lowest[i]) {
m += parseFloat(score());
count += 1;
}
}
});
if (count) {
m = m / count;
return m.toFixed(2);
} else {
return 'N/A';
}
});
}
Update 2
Just in case someone else wanders over here since my problem isn't solve still. The following code is how I set the value of lowest:
this.dropLowestScores = function() {
ko.utils.arrayForEach(_this.students(), function(student){
var comparator = function(a,b){
if(a()<b()){
return 1;
} else if(a() > b()){
return -1;
} else {
return 0;
}
};
var tmp = student.scores().slice(0);
tmp.sort(comparator);
student.lowest = ko.observableArray(tmp.splice((tmp.length-2),tmp.length-1));
});
};
Outstanding Questions, 5/9/2014
Jeremy's script runs but without the desired effects. For example, console.log(_this.lowest[k]) prints undefined, just as mine does. Further, the matched scores aren't skipped, which they should be.
Jeremy's script specifies lowest as a ko.observable. My script also now has lowest as a ko.observable, but why shouldn't a plain JS array work for this? I only need lowest to update when the button it's bound to is clicked, and those bindings are already taken care of.
That is how observables work in Knockout.
When you create one, you are creating a function.
var myObservable1 = ko.observable(); // Create it.
var myObservable2 = ko.observable("Hola!"); // Create it with a value.
console.log(typeof myObservable2); // It is indeed a function
console.log(typeof myObservable2()); // That returns a string
console.log(myObservable2()); // And get the value.
EDIT BASED ON QUESTION IN COMMENTS
var koTest = ko.observableArray();
koTest.push("Line0");
koTest.push("Line1");
koTest.push("Line2");
koTest.push("Line3");
koTest.push("Line4");
var jsTest = [];
jsTest.push("Line0");
jsTest.push("Line1");
jsTest.push("Line2");
jsTest.push("Line3");
jsTest.push("Line4");
alert(koTest()[2]);
alert(jsTest[2]);
alert(koTest()[2] === jsTest[2]);
Test Code
I went ahead and make a runnable test of your code and everything was working just fine for me. I had to make some assumptions about the contents of _this -- in particular the declaration of lowest, which I made an observableArray based on how you were accessing it.
Anyways, this code runs:
var _this = {
scores: ko.observableArray(),
lowest: ko.observableArray()
};
var mean = (function(scores) {
var m = 0;
var count = 0;
var k;
ko.utils.arrayForEach(_this.scores(), function(score) {
console.log([typeof score(), score()]);
if (!isNaN(parseFloat(score()))) {
k = _this.scores.indexOf(score);
console.log(k);
console.log(_this.lowest[k]);
if (score() != _this.lowest[k]) {
m += parseFloat(score());
count += 1;
}
}
});
if (count) {
m = m / count;
return m.toFixed(2);
} else {
return 'N/A';
}
});
for (var i = 0; i < 10; i++) {
_this.scores.push(ko.observable(i));
}
var m = mean();
alert(m);
I am new in JSON, i am trying to save data using JSON. I have a list of element with some button when we click the button i want the corresponding value of button are save in JSON. I am also want to compare the title with already exists in JSON.
Demo Here
You can simply use a for loop to check if the element with that title is already there:
function alreadyAdded(itemTitle) {
for (var i = 0; i < objArray.length; i++) {
if (objArray[i].title === itemTitle) {
return true;
}
}
return false;
};
Also, you are not using a json object, just a JavaScript array.
Demo
try this
http://jsfiddle.net/Z3v4g/
var counter = 0;
var jsonObj = []; //declare object
$('.imgbtn').click(function () {
var title = $(this).parent().parent().find('span').html();
var image = $(this).parent().parent().find('img').prop('src');
for( var i=0; i<jsonObj.length; i++){
if( jsonObj[i].title == title ) return false;
};
counter++;
$('#lblCart').html(counter);
jsonObj.push({
id: counter,
title: title,
image: image,
description: 'Example'
});
});
I am assuming you want to store values in an array, and during a button click you want to check if the item already exists in the array. If this is true, then you can use the following code -
var counter = 0;
var jsonObj = []; //declare object
$('.imgbtn').click(function () {
var title = $(this).parent().parent().find('span').html();
var image = $(this).parent().parent().find('img').prop('src');
var match = $.grep(jsonObj, function (e) {
return e.title == title;
});
if (match.length > 0) {
// This title already exists in the object.
// Do whatever you want. I am simply returning.
return;
}
counter++;
$('#lblCart').html(counter);
jsonObj.push({
id: counter,
title: title,
image: image,
description: 'Example'
});
});
Notice that I have declared the array outside the callback function. This ensures that all the invocation of the callback operate on the same array object. Declaring it inside the callback was only making it available for a single callback invocation.
Also note that you are simply using an array to store plain JavaScript Objects.
Demo.
First:
var jsonObj = []; //declare object
This is not a JSON. This is an Array. JSON is just the notation of Javascript Object. To declare a object you should do:
var jsonObj = {};
or:
var jsonObj = new Object();
After this, you can approach what you asked doing this:
var counter = 0;
var jsonObj = new Object();
$('.imgbtn').click(function () {
var title = $(this).parent().parent().find('span').html();
var image = $(this).parent().parent().find('img').prop('src');
if (!(title in jsonObj)) { // if item is not in the object, (title in jsonObj) returns true of false
jsonObj[title] = { // When you have hundreds of items, this approach is way faster then using FOR loop, and if you need to alter the item or get one value, you can just call it by name: jsonObj['ABC'].image will return the path of the image
id: counter,
image: image,
description: 'Example'
}
counter++;
$('#lblCart').html(counter);
} else {
// Do what you want if the item is already in the list
alert('Item already in the list');
console.log(jsonObj[title]);
}
});
DON'T use FOR loops to do what you wan't, it will just slow down your application if the counter gets high.