$localStorage is not adding new items with the old items - angularjs

I want to add new items into $localStorage plus old items. But, here in my code $localStorage loosing all previous items. My code is as follows,
$scope.cart = [];
$scope.cart = productService.getSharedProduct();
if ($scope.cart != 0) {
$localStorage.items = $scope.cart;
}
else {
$scope.cart = $localStorage.items;
}

Yes because you are not adding items to your $localStorage.items but you are assigning new values to it every time and so it lost the last added values.
You are re-initializing them every time and so they loose last added values.
You should do something like this
if ($scope.cart != 0) {
// instead of this
//$localStorage.items = $scope.cart;
// you should do this
for(var i=0; i<$scope.cart.length; i++)
{
$localStorage.items.push($scope.cart[i]);
}
}

Related

Infinite Digest Loop in AngularJS filter

I have written this custom filter for AngularJS, but when it runs, I get the infinite digest loop error. Why does this occur and how can I correct this?
angular.module("app", []).
filter('department', function(filterFilter) {
return function(items, args) {
var productMatches;
var output = [];
var count = 0;
if (args.selectedDepartment.Id !== undefined && args.option) {
for (let i = 0; i < items.length; i++) {
productMatches = items[i].products.filter(function(el) {
return el.Order__r.Department__r.Id === args.selectedDepartment.Id;
});
if (productMatches.length !== 0) {
output[count] = {};
output[count].products = productMatches;
output[count].firstProduct = items[i].firstProduct;
count++;
}
}
}
return output;
};
}).
This is the relevant HTML:
<tr class='destination' ng-repeat-start='pickupAccount in pickupAccounts | department : {"selectedDepartment": selectedDepartment, "option": displayExclusive }'>
<!-- td here -->
</tr>
displayExclusive is boolean.
I have written this custom filter for AngularJS, but when it runs, I get the infinite digest loop error.
Keep in mind that filter should return array of the same object structure. When we activate filter, it fires digest cycle that will run over our filter again. If something changed in output list - fires new digest cycle and so on. after 10 attempts it will throw us Infinite Digest Loop Exception
Testing
This empty filter will works (100%). Actually we do nothing here but return the same object that filter receives.
filter('department', function(filterFilter) {
return function(items, args) {
var output = items;
return output;
};
})
Now the main idea is: write some condition to push to output objects from input list a.e. items based on some if statement, a.e.
var output = [];
if (args.selectedDepartment.Id !== undefined && args.option) {
angular.forEach(items, function(item) {
if(<SOME CONDITION>) {
output.push(item);
}
});
}
By this way it will work too.
our case:
we have this logic:
productMatches = items[i].products.filter(function(el) {
return el.Order__r.Department__r.Id === args.selectedDepartment.Id;
});
if (productMatches.length !== 0) {
output[count] = {};
output[count].products = productMatches;
output[count].firstProduct = items[i].firstProduct;
count++;
}
Here we completely modified object that has been stored in output.
So next digest cycle our items will change again and again.
Conclusion
The main purpose of filter is to filter list and not modify list object content.
Above mentioned logic you wrote is related to data manipulation and not filter. The department filter returns the same length of items.
To achieve your goal, you can use lodash map or underscorejs map for example.
This happens when you manipulate the returned array in a way that it does not match the original array. See for example:
.filter("department", function() {
return function(items, args) {
var output = [];
for (var i = 0; i < items.length; i++) {
output[i] = {};
output[i] = items[i]; // if you don't do this, the next filter will fail
output[i].product = items[i];
}
return output;
}
}
You can see it happening in the following simplified jsfiddle: https://jsfiddle.net/u873kevp/1/
If the returned array does have the same 'structure' as the input array, it will cause these errors.
It should work in your case by just assigning the original item to the returned item:
if (productMatches.length !== 0) {
output[count] = items[i]; // do this
output[count].products = productMatches;
output[count].firstProduct = items[i].firstProduct;
count++;
}
output[count] = {};
Above line is the main problem. You create a new instance, and ng-repeat will detect that the model is constantly changed indefinitely. (while you think that nothing is changed from the UI perspective)
To avoid the issue, basically you need to ensure that each element in the model remains the 'same', i.e.
firstCallOutput[0] == secondCallOutput[0]
&& firstCallOutput[1] == secondCallOutput[1]
&& firstCallOutput[2] == secondCallOutput[2]
...
This equality should be maintained as long as you don't change the model, thus ng-repeat will not 'wrongly' think that the model has been changed.
Please note that two new instances is not equal, i.e. {} != {}

How to delete the array with index 2 in local storage?

My local storage looks like this
{"data":[[0,"Post1","Text1","2016-12-16T11:01:00.000Z"],[1,"Post2","Text2","2016-12-20T14:00:00.000Z"]],[3,"Post3","Text3","2016-12-25T13:00:00.000Z"]]}
How can I delete only one item in the array?
I have tried with this, where postid is the array index I want to delete.
var postid = 1
var info = JSON.parse(localStorage.getItem("rp_data"));
var obj = [];
for(var i = 0; i < info.data.length; i++){
var data = info.data[i];
if(data === postid){
info.splice(i, 1);
}
}
localStorage.setItem("rp_data", JSON.stringify(data));
So the if part is wrong I guess!?
Any input appreciated, thanks.
UPDATE
So with this I can remove one of the posts in the array, where the first item in the array is equal to my postid, so if the postid=1 it will remove the second post in the array.
//var postid = $$(this).attr('data-id');
//postid=parseInt(postid)
postid=1
var info = JSON.parse(localStorage.getItem("rp_data"));
//remove object
for(var i = 0; i < info.data.length; i++){
var data = info.data[i][1];
myApp.alert(data);
if(i === postid){
myApp.alert(i);
info.data.splice(i, 1);
}
}
localStorage.removeItem("rp_data");
localStorage.setItem("rp_data", JSON.stringify(info));
So I have 1 more problems.
If I use postid=1 as above it works and it creates a new local storage with the right values. But if get the value from my form and then try to convert the string to a number it stops working.
This does not work, like it is not converting the string to a number?
var postid = $$(this).attr('data-id');
postid=parseInt(postid)
So why is this not converting it to a number?
Since the items in the array are JSON objects, you cannot compare the object to postid. You should use indexOf. You also don't want to splice the index. This should be the object or item in this case. If you want to remove the item in the object, you would have to iterate through the object as well. So this would be a nested loop.
//remove object
for(var i = 0; i < info.data.length; i++){
var data = info.data[i];
if(i === postid){
info.data.splice(data, 1);
}
}
//remove item in object
for(var i = 0; i < info.data.length; i++){
if(i == postid){
for(var j = 0; j < info.data[i].length; j++){
var item = info.data[i][j];
info.data[i].splice(item,1);
}
}
}

delete multiple selected items from the list angular js

I am trying to delete the one or more selected items in the list in angular js.
I tried to add the items in the following way:
$scope.selectedNodes = [];
$scope.addItem = function(e) {
$scope.selectedNodes.push({
id :$scope.selectedNodes.length + 1,
Nodeid: e.item.id,
title: e.item.text});
$scope.$apply();
}
html is as below:
<select ng-model="selectedItems" multiple ng-multiple="true">
<option ng-repeat="node in selectedNodes" value="{{node}}">{{node}}</option>
</select>
<button ng-click="remove(selectedItems)" type="submit">
Remove
</button>
The above html is listing fine with all the items.
Now I am trying to delete one or more items from the list, so the code I have written is:
$scope.remove = function (nodes) {
alert(nodes); // it's giving the selected records info, no problem with it
angular.forEach(nodes, function (node) {
var index = $scope.selectedNodes.indexOf(node);
alert(index) //problem here, it's always -1
$scope.selectedNodes.splice(index, 1);
});
};
The above code is removing the last item if one item is selected. And if more than one is selected, let's say two, it's then removing the last two records.
The index value is always -1 for any no. of iterations in the foreach loop.
Could anyone please help with the above code to delete one or more selected records and the list should get refreshed. No problem with refreshing for the above code.
I tried as you mentioned below, but no luck.
$scope.remove = function (nodes) {
alert(nodes); // it's dispalying correct results
for(var i = 0; i< nodes.length; i++)
{
alert(nodes.length); // correct result, no problem
alert(nodes[i]); //correct result, no problem
alert(nodes[i].Nodeid); // problem, value Nodeid is Undefined
for (var idx = 0; idx < $scope.selectedNodes.length; idx++) {
alert($scope.selectedNodes[idx].Nodeid);
if ($scope.selectedNodes[idx].Nodeid == nodes[i].Nodeid) {
$scope.selectedNodes.splice(idx, 1);
break;
}
}
};
};
You're trying to locate the node using indexOf, which compares values using the strict '===' operator, and you're trying to compare objects.
I think it would be easier for you to use one of the many libraries outthere for collection manipulation (lodash, underscore, etc) but if you want to do it as you were doing then this is the code:
$scope.remove = function (nodes) {
angular.forEach(nodes, function (node) {
for (var idx = 0; idx < $scope.selectedNodes.length; idx++) {
if ($scope.selectedNodes[idx].Nodeid == node.Nodeid) {
$scope.selectedNodes.splice(idx, 1);
break;
}
}
});
};
If the number of nodes to delete is very high and you're concerned about optimization then you can iterate the selectedNodes array in inverse order and be deleting the node if it's in the nodesToDelete collection. The code structure is similar, just iterating outside the selectedNodes and inside the nodesToDelete.

Angular values update in both elements

I am adding same element (json object) into a list (from another list) twice using .copy to break the reference. But even after doing that when I change some values in one both of them are getting updated.
$scope.addProduct = function (item) {
var index = $scope.itemsProduct.indexOf(item);
$scope.scopItem = {};
angular.copy(item , $scope.scopItem);
for(var j in $scope.scopItem['ABC']) {
$scope.scopItem['ABC'][j].dataType='Discount';
$scope.scopItem['ABC'][j]['Discount'] = '';
}
if (index != -1) {
$scope.itemsTags.push($scope.scopItem);
$timeout(function() {
$scope.$apply(function () {
$scope.calculate($scope.scopItem);
});
}, 10);
}
};
$scope.calculateParam = function (indexQ) {
var index = $scope.itemsTags.indexOf(indexQ);
$scope.itemsTags[index]['ABC']['Discount'] = '10'; //or some other logic
}
Need help as even i am not adding the same element(using .copy) and updating the "Discount" property of one updates both??
Note: ABC is a inner list with property as "Discount" and I am changing "Discount"
Some comments:
for(var j in $scope.scopItem['ABC'])
it's absolutely incorrect and should be rewrited to
for(var j=0; j < $scope.scopItem['ABC'].length; j++)
also scopItem is changed in calculate method and stored in itemsTags

Angularjs array changes reference after splice

I am using angularjs for my project and its working fine. Today I am facing little but different problem
so just need some kind of suggestion.
Consider code :
$scope.deleteEmpty = function(){
for(var sp=0;sp < $scope.column.length;sp++){
var offerings = $scope.column[sp];
if(offerings.spName == -1){
$scope.removeanswer(sp);
}
}
},
$scope.removeanswer = function(position){
for(var question=1;question<$scope.rows.length;question++){
$scope.rows[question].answerlst.splice(position, 1);
}
},
here i am deleting answerlst according to offerings position, it is getting deleted but the there is one problem. Consider one example:
$scope.column = [{'spName':'-1',spId:'1'},{'spName':'-1',spId:'2'},{'spName':'-1',spId:'3'},{'spName':'-1',spId:'4'}]
when first time call to $scope.removeanswer(sp); it delete answerlst for first column but after that the position of answerlst get changed. So it deletes for 1st and 3rd position and not for the whole.
Any suggestion please.
Thanks.
The following solution could be improved if there was more information.
The idea is to store the column indexes in a toRemove array and then remove them all at once from the answerlst of each question.
$scope.deleteEmpty = function(){
var toRemove = []; // column indexes to be removed
for(var sp=0;sp < $scope.column.length;sp++){
var offerings = $scope.column[sp];
if(offerings.spName == -1){
toRemove.push(sp);
}
}
$scope.removeanswer(toRemove);
},
$scope.removeanswer = function(positions){
for(var question=1;question<$scope.rows.length;question++){
$scope.rows[question].answerlst = $scope.rows[question].answerlst.filter(function(value, index) {
return positions.indexOf(index) < 0;
});
}
},

Resources