David Panart
David Panart

Reputation: 656

Removing an element from an array of Object

I'm building a live notification system with Meteor, but as I've never done this before, I'm certainly tricking to get something that works.

I have a <ul> list of notifications. I defined an event clicking on the <a class="notif-link"> that each <li> contains.

My notifications have an ID, a type, and some other stuff we do not care about.

notifications:
    [
         {id: 0, type: 0, img: null, link: "/profile"},
         {id: 1, type: 1, img: null, link: "/profile"},
         {id: 2, type: 2, img: null, link: "/profile"},
         {id: 3, type: 3, img: null, link: "/profile"},
    ]

...

Template.navigation.events({
       "click .notif-link": function(e, tmpl){
           console.log(EJSON.stringify(this)); // print the verbosed notification object as shown above
           var index = Meteor.user().profile.notifications.indexOf({id: this.id});
           console.log(index); // always == -1
           newNotifArray = Meteor.user().profile.notifications.splice(index, 1);
           Meteor.users.update({_id: Meteor.userId()}, {$set: {'profile.notifications': newNotifArray}});
       }
   });

The notification.id is set as the <a> #id, which should allow me to identify the notification in the array and delete it when the link is clicked.

The problem is that notification.indexOf({id : this.id}) always return me -1. I guess the problem is that I do not know how to work properly on an array of objects.

Can someone explain to me how to deal with it ?

Thanks you.

Upvotes: 0

Views: 157

Answers (2)

asimen1
asimen1

Reputation: 21

The problem is your attempting to find the index of an new object you created: {id: this.id}, inside the array of notifications objects you defined, which obviously does not include it.

Array.IndexOf when given an object to search for, will attempt to find the same object (pointer in memory) in the array, so you can't really use it unless you have the actual object. For instance: notifications.indexOf({id: 0, type: 0, img: null, link: "/profile"}), will also return -1 since its a different object even though has the same values.

I am not familiar with Meteor, but there are libraries that can help you in this cases, for example underscore is very helpful for array and list helpers. For this case you can use underscores's findWhere method like so:

_.notifications.findWhere({id: this.id})

This will return the actual object in the array which matches the attributes you specified, with the actual object you can then use Array.indexOf to get the index of the object inside the array.

I'm sure that are a lot of other ways and libraries to do this, depends on what you are already using. Here are some links to additional solutions not using underscore:

using pure Javascript map - indexOf method in an object array?

using JQuery grep - Find object by id in an array of JavaScript objects

Cheers.

Upvotes: 2

Peter Ilfrich
Peter Ilfrich

Reputation: 3816

You're looking for an object called: {id: 1}, but your notification entries are larger. They contain other fields as well (not just an ID field). You're mixing up standard JavaScript comparison with MongoDB queries.

Have a look at MongoDBs $pull operation. Something like:

Meteor.users.update({_id: Meteor.userId}, { $pull: {
    'profile.notifications': { id: this.id },
}});

(I haven't tested this code, not entirely sure about the id: this.id query..)

Loading the data into memory, modifying it there and then writing it back might seem intuitive (I did the same thing at first^^), but operating directly on the database is a) more efficient and b) much more elegant.

Upvotes: 1

Related Questions