0

I have 2 arrays within my Ember application, one array holds a string of ID's and another holds Ember objects.

I want to send the Ember objects to a function, get the array of ID's from a cookie stored in the browser and then filter out the Ember objects if the ID property corresponds to a string in my array of IDS.

I am attempting to use filter for this but every time it just brings back the full list of Ember objects, even if there ID is held in the ID string array. Here is my code from my Ember component..

init () {
        this._super(...arguments);

this.get('userNotificationServices').fetchActiveUserNotifications().then(result => {
            this.updatedArray = this.filterArray(result);
            this.set('activeNotifications', result);
        });

    },

filterArray(currentActiveNotifications) {
    var ids;
    var currentNonDimissedNotifications;
    if (this.getCookie("dismissed-notifications")) {
        ids = this.getCookie("dismissed-notifications").split(',');
        currentNonDimissedNotifications = currentActiveNotifications.filter(function (obj) {
            for (var id in ids) {
                return obj.id !== id;
            }
        });
    }
    return currentNonDimissedNotifications;
}
N P
  • 2,319
  • 7
  • 32
  • 54
  • Use set method `this.set('updatedArray', this.filterArray(result));` instead of directly assigning it like this `this.updatedArray = this.filterArray(result);` – Ember Freak Mar 21 '17 at 10:39

2 Answers2

1

There are two problems with your filter:

currentNonDimissedNotifications = currentActiveNotifications.filter(function (obj) {
    for (var id in ids) {
        return obj.id !== id;
    }
});
  1. It always returns the result of the first check it does; it never does subsequent checks, because you're using return unconditionally.

  2. You've used for-in, which means id will be the index of each entry, not its value. More about looping arrays, and why for-in isn't the right too most of the time, in my answer here.

We want to only return when we've either found a match (we can stop right away) or have looped through the whole array of IDs, and we want to loop correctly.

So it could be:

currentNonDimissedNotifications = currentActiveNotifications.filter(function (obj) {
    for (var i = 0; i < ids.length; ++i) { // Note loop
        if (obj.id === ids[i]) {
            // Found it, so we want to filter it out
            return false;
        }
    }
    // Didn't find it, so keep it
    return true;
});

Live Example:

var currentActiveNotifications = [
  {id: 1},
  {id: 2},
  {id: 3}
];
var ids = [2, 3];
var currentNonDimissedNotifications = currentActiveNotifications.filter(function (obj) {
    for (var i = 0; i < ids.length; ++i) { // Note loop
        if (obj.id === ids[i]) {
            // Found it, so we want to filter it out
            return false;
        }
    }
    // Didn't find it, so keep it
    return true;
});
console.log(currentNonDimissedNotifications);

...but arrays have a handy function called indexOf that lets us check if a value is in an array (newer versions of JavaScript also have includes). So we can use that:

currentNonDimissedNotifications = currentActiveNotifications.filter(function (obj) {
    return ids.indexOf(obj.id) === -1;
});

Live Example:

var currentActiveNotifications = [
  {id: 1},
  {id: 2},
  {id: 3}
];
var ids = [2, 3];
var currentNonDimissedNotifications = currentActiveNotifications.filter(function (obj) {
    return ids.indexOf(obj.id) === -1;
});
console.log(currentNonDimissedNotifications);

Or with the newer includes:

currentNonDimissedNotifications = currentActiveNotifications.filter(function (obj) {
    return !ids.includes(obj.id);
});

Live Example:

var currentActiveNotifications = [
  {id: 1},
  {id: 2},
  {id: 3}
];
var ids = [2, 3];
var currentNonDimissedNotifications = currentActiveNotifications.filter(function (obj) {
    return !ids.includes(obj.id);
});
console.log(currentNonDimissedNotifications);
Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thank you, is there a way to do this, so if we have multiple ids that are present in both array it removes each one from the parent array? – N P Mar 21 '17 at 10:17
  • As If I have say ID 1,2 in my first array and ID 1,2 in my second array, I want to return an empty array, is this possible? – N P Mar 21 '17 at 10:20
  • @NickPocock: That's what the above does. I've added live examples (and fixed the `includes` one, I was missing a `!`). – T.J. Crowder Mar 21 '17 at 10:31
0

You should not use for-loop to filter objects, because return obj.id !== id; will always return true, and it only checks the first id also.

Try to use indexOf:

currentNonDimissedNotifications = currentActiveNotifications.filter(function(obj) {
  return ids.indexOf(obj.id) === -1
});
dfsq
  • 191,768
  • 25
  • 236
  • 258