I have an event that attempts to remove items from a list. Currently trying to use splice to remove them from the array of objects. I need to use a function that acutally uses the original array. As I want so see the change happen live in the frontend. The code below works to a certain extent, but only seems to remove some items per click.
Controller
$scope.clearAlerts = function(type) {
var array = [];
for (let item of $scope.notifications) {
if (item.read && type == 'seen') {
notifications.clearAlerts(item.watching_id);
//console.log(item.watching_id)
}
if (!item.read && type == 'notseen') {
notifications.clearAlerts(item.watching_id);
//console.log(item.watching_id) - This returns 8 items
}
}
}
Service
this.clearAlerts = function(watchingId = null) {
// Remove notifications
this.notifications.forEach((item, index, object) => {
if (item.watching_id === watchingId) {
//remove alerts from dom
object.splice(index, 1); - This only removes 2 or 3 per click
index--;
// update database
//return api.request('GET', 'notification/' + watchingId + '/clear', {watching_id: watchingId});
}
});
}
Any help on this would be much appreciated. Thanks
So if you were to use an object instead of an array where the keys of the object were say the ID you are watching then your service function should look something like this...
this.clearAlerts = function(watchingId = null) {
delete this.notifications[watchingId];
}
Much simpler, so the idea is that instead of using an array as in [object, object], us an object that is mapped out something like so
{
id1: object,
id2: object,
...
}
where id1, and id2 are actually taken from watching_id which you defined
As for the reason why your alerts aren't removed accurately is because you are mutating the array you are looping through.
Here is an example
const notifications = [
{
watching_id: 1
},
{
watching_id: 2
},
{
watching_id: 3
},
{
watching_id: 4
}
];
notifications.forEach((item,index, arr) => {
if (item.watching_id > 0) {
arr.splice(index, 1);
}
})
In this example at first sight it can seem that all items are going to be deleted, but that is not the case.
When the index is 0, you delete the first item, and after deletion you have an array with 3 items, so on the second iteration when the index is 1 you are deleting the item from 3 items array which index is 1 and that is the second item out of 3, the first item is intact.
As a solution you can add the third argument to the splice, in order to have the same length array, which will solve the problem. Decide yourself what is best for your specific case, 3rd argument can be anything null,'undefined' or an object object.splice(index, 1, {}).
By the way, index-- doesn't do anything, index is set on every iteration.
Related
I've got an array that looks like:
Is there a way that when another object "AAPL" gets added to the array, the fees and amount gets added and AAPL stays one object in the array?
Thank you in advance!
I wouldn't want to assume that "AAPL" is always within the array.
Check first if the new item is within the array. If not, I will return and end the call (but you may wish to append this to the array instead as it is a new item).
If it is, replace the current object (or parts of the object, in this case I have done just fees & amount)
function addPortfolioItem(item) {
const index = returnPortfolioHoldingIndex(item);
if (index = -1) {
// Returning if not found - You may wish to append to the array as mentioned above
return;
} else {
// Overwrite the object within the array with the new object
portfolioHoldings[index].fees = item.fees;
portfolioHoldings[index].amount = item.amount;
}
}
function returnPortfolioHoldingIndex() {
const tickerSymbolToSearch = "AAPL";
return portfolioHoldings.findIndex(item => item.ticker_symbol === tickerSymbolToSearch);
}
First identify the entry then just add another integer to the value.
It depends on how you are updating that object now - if it's always in 0 position then just portfolioHoldings[0][amount] += number;
if not, then loop through all and check if ticker_symbol == AAPL, then update that array value, by adding needed amount.
Title is pretty much self explanatory...
I want to be able to find duplicated values from JavaScript array.
The array keys can be duplicated so I need to validate only the array values.
Here is an example :
var arr=[
Ibanez: 'JoeSatriani',
Ibanez: 'SteveVai',
Fender: 'YngwieMalmsteen',
Fender: 'EricJohnson',
Gibson: 'EricJohnson',
Takamine: 'SteveVai'
];
In that example:
the key is the guitar brand
the value is the guitar player name.
So:
If there is duplicated keys (like: Ibanez or Fender) as on that current example that is OK :-)
But
If there is duplicated values (like: EricJohnson or SteveVai) I'm expecting to get (return) that error:
EricJohnson,SteveVai
You can't have associative arrays in Javascript. You can create an array of objects, like:
var arr=[
{Ibanez: 'JoeSatriani'},
{Ibanez: 'SteveVai'},
{Fender: 'YngwieMalmsteen'},
{Fender: 'EricJohnson'},
{Gibson: 'EricJohnson'},
{Takamine: 'SteveVai'}
];
Then you'll need a for...in loop to go over every object in the array, create a new array of values and check that for duplicates, which is also not very straightforward - basically you'll want to sort the array and make sure no value is the same as the one after it.
var arrayOfValues = [];
arr.forEach(function(obj){
for(var prop in obj)
arrayOfValues.push(obj[prop]);
});
arrayOfValues.sort(); // by default it will sort them alphabetically
arrayOfValues.forEach(function(element,index,array){
if(array[index+1] && element==array[index+1])
alert("Duplicate value found!");
});
First of all, object keys can not be repeated.
This means that:
({
"Fender": "Jim",
"Fender": "Bob"
})["Fender"]
Would simply return: "Bob".
However, I did make a code that could allow you to find duplicates in values, but as I said, the key will have to be unique:
var arr = {
Ibanez: 'EricJohnson',
Fender: 'YngwieMalmsteen',
Gibson: 'EricJohnson',
Takamine: 'SteveVai',
"Takamine2": 'SteveVai'
};
function contains(a, obj) {
for (var i = 0; i < a.length; i++) {
if (a[i] === obj) {
return true;
}
}
return false;
}
var track = [];
var exists = [];
for (var val in arr) {
if (contains(track, arr[val])) {
exists.push(arr[val]);
} else {
track.push(arr[val])
}
}
alert(exists)
You can see it working here: http://jsfiddle.net/dr09sga6/2/
As others have commented, the example array you provided isn't a valid JavaScript array. You could, however, keep a list for each guitar type:
var mapping = {
Ibanez: ['JoeSatriani','SteveVai'],
Fender: ['YngwieMalmsteen','EricJohnson']
Gibson: ['EricJohnson'],
Takamine: ['SteveVai']
];
Or a list of each guitar/musician pair:
var pairs = [
['Ibanez','JoeSatriani'],
['Ibanez','SteveVai'],
['Fender','YngwieMalmsteen'],
['Fender','EricJohnson'],
['Gibson','EricJohnson'],
['Takamine','SteveVai']
];
Your solution is going to depend on which pattern you go with. However, in the second case it can be done in one chained functional call:
pairs.map(function(e) {return e[1]}) // Discard the brand names
.sort() // Sort by artist
.reduce(function(p,c,i,a){
if (i>0 && a[i]==a[i-1] && !p.some(function(v) {return v == c;})) p.push(c);
return p;
},[]); //Return the artist names that are duplicated
http://jsfiddle.net/mkurqmqd/1/
To break that reduce call down a bit, here's the callback again:
function(p,c,i,a){
if (i>0
&& a[i]==a[i-1]
&& !p.some(function(v) {
return v == c;
}))
p.push(c);
return p;
}
reduce is going to call our callback for each element in the array, and it's going to pass the returned value for each call into the next call as the first parameter (p). It's useful for accumulating a list as you move across an array.
Because we're looking back at the previous item, we need to make sure we don't go out of bounds on item 0.
Then we're checking to see if this item matches the previous one in the (sorted) list.
Then we're checking (with Array.prototype.some()) whether the value we've found is ALREADY in our list of duplicates...to avoid having duplicate duplicates!
If all of those checks pass, we add the name to our list of duplicate values.
I have a select field which on change I get the value. As I am looping through the select values I want to detect if it matches the value I have if it does I also want to check if the object contains a flag===true I wrote in. All I keep getting is the amount of items in the array and whatever the last one's flag is what the final value is.
array[
object{
value: fromSelectChange //if matches && flag is set to true stop looping
flag: true
}
]
assuming array is you array
var array = [
{value: fromSelectChange, flag: true},
. . . // others
];
just use
function match(arr, value){
var totalOk = 0;
arr.every(function(el){
if(el.flag && value == el.value){
totalOk++;
}
});
return totalOk;
}
alert(match(array))
My First reaction would be to throw it all into a for in loop. I usually find it one of the easier ways to see if something iterating on arrays will work.
var fromSelectChangeReturn;
for (index in array) {
if (array[index].fromSelectChange == value && array[index].flag) {
fromSelectChangeReturn = array[index].fromSelectChange;
Break;
}
}
For in MDN page: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
Let's imagine I have this array:
bucket.bucketList =[];
bucket.addItem = function(item) {
bucket.bucketList.push(item);
}
The function pushes an object called foo this into the array on every mouse-scroll:
Some foo's also have a property , foo.name = "something";
The question is, what is the best way to delete All duplicates based on their name property names whilst keeping the most recents one pushed in?
I am using jQuery already in my project, so if jQuery has a more elegant way of doing this than vanilla JS i'd be more than happy to use it.
This code removes all duplicate names, keeping the last one in the array.
You can traverse backwards through the array and remove any items with a name that you've already seen, using an object to keep track of the names you've already seen. By traversing backwards, you keep the last one and you don't have to do any array index corrections when you remove the current entry from the array:
var dict = {}, item;
for (var i = bucket.bucketList.length - 1; i >= 0 ; i--) {
item = bucket.bucketList[i];
if (item.name) {
// if already in the dict, remove this array entry
if (dict[item.name] === true) {
bucket.bucketList.splice(i, 1);
} else {
// add it to the dict
dict[item.name] = true;
}
}
}
How do I remove an item[i] from items once it reaches in:
$.each(items, function(i) {
// how to remove this from items
});
It would be better not to use $.each in this case. Use $.grep instead. This loops through an array in pretty much the same way as $.each with one exception. If you return true from the callback, the element is retained. Otherwise, it is removed from the array.
Your code should look something like this:
items = $.grep(items, function (el, i) {
if (i === 5) { // or whatever
return false;
}
// do your normal code on el
return true; // keep the element in the array
});
One more note: this in the context of a $.grep callback is set to window, not to the array element.
I'm guessing you want $.map. You can return null to remove an item, and not worry about how indices might shift:
items = $.map(items, function (item, index) {
if (index < 10) return null; // Removes the first 10 elements;
return item;
});
If you want to remove an element from array, use splice()
var myArray =['a','b','c','d'];
var indexToRemove = 1;
// first argument below is the index to remove at,
//second argument is num of elements to remove
myArray.splice(indexToRemove , 1);
myArray will now contain ['a','c','d']
the solution is below:
_.each(data, function (item, queue) {
if (somecondition) {
delete data[queue]
}
});
Something like
var indexToBeRemoved = 3; // just an illustration
$.each(items, function(i) {
if(i==indexToBeRemoved){
$(this).remove();
}
});
As mentioned by #lonesomday above (I simply couldn't add this in a comment) grep is for Arrays, but you could insert your selector inside grep:
var items = $.grep($(".myselector", function (el, i) {
return (i===5) ? false : true;
};
This would store all elements found using $(".myselector")in ìtems` leaving out the item at the 6th position (the list is 0 indexed, which makes "5" the 6th element)
Although I would typically prefer using $.grep() to filter the array, I have an instance where I'm already using $.each() on the array to process a dataset. After doing some processing, I can determine whether or not the item needs to be removed from the array:
// WARNING - DON'T DO THIS:
$.each(someArray, function(index, item) {
// Some logic here, using 'item'
if (removeItem) {
// Spice this item from the array
someArray.splice(index, 1)
}
// More logic here
});
WARNING: This presents a new problem! Once the item has been spliced from the array, jQuery will still loop for the length of the original array. E.g.:
var foo = [1,2,3,4,5];
$.each(foo, function(i, item) {
console.log(i + ' -- ' + item);
if (i == 3){
foo.splice(i, 1);
}
});
Will output:
0 -- 1
1 -- 2
2 -- 3
3 -- 4
4 -- undefined
And foo is now [1, 2, 3, 5]. Every item in the array is "shifted" relative to the jQuery loop, and we missed the element "5" altogether, and the last item in the loop is undefined. The best way to solve this is to use a reverse for loop (going from arr.length - 1 to 0).
This will ensure that removing an element won't affect the next item in the loop. However since the question here is with respect to $.each, there are a few alternative ways of solving this:
1) $.grep() the array before looping
var someArray = $.grep(someArray, function(item) {
// Some logic here, using 'item'
return removeItem == false;
});
$.each(someArray, function(index, item) {
// More logic here
});
2) Push items into another array
var choiceArray = [ ];
$.each(someArray, function(index, item) {
// Some logic here, using 'item'
if (removeItem) {
// break out of this iteration and continue
return true;
}
// More logic here
// Push good items into the new array
choiceArray.push(item);
});