Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular / lodash - remove multiple objects from a collection

SOLUTION TO MY ORIGINAL QUESTION

Thanks to the brilliance of Dan's answer below I've managed to reduce my original code significantly. I have dropped some of flexibility I originally had built i.e. use multi properties vs static prop, but an easy fix in a later version and a no-brainer in terms of code size :) Again, many thanks to Dan. In this example I've included 2 forget() methods wrapped in an Angular Collection factory.

Collection.$inject = ['Constructor', 'Article'];
function Collection(Constructor, Article) {

    var Model = Article,
        Collection = {},
        collection = [],
        add,
        forget;

    function Extendable(data, keys) {
        Constructor.call(this, data, Model.fillable);
    }

    Extendable.prototype = Object.create(Constructor.prototype);
    Extendable.prototype.constructor = Extendable;
    Collection = Extendable.prototype;
    collection = Collection.items = [];

    add = function(item) {
        if (item instanceof Model) {
            collection.push(item);
        }
    };
    Collection.add = add;

    // EXAMPLE OF SINGLE ID DELETE I.E. SIMPLE VERSION
    forget = function(id) {
        collection = _.dropWhile(collection, {id: id});
    };
    Collection.forget = forget;

    // OR!!! EXAMPLE OF MULTI ID VALUE || ARRAY
    forget = function(id) {
        var ids = [];
        if (_.isArray(id)) {
            ids = id;
        } else {
            ids.push(parseInt(id));
        }
        return _.dropWhile(collection, function (n) {
            return _.includes(ids, n.id);
        });
    };
    Collection.forget = forget;

    // remove rest of factory for brevity sake
    return Extendable;
};

DEV TOOLS

Angular 1.4.8, lodash 2.x

QUESTION:

I'm still an Angular & JS. Is there a more concise approach to deleting multiple object instances (e.g. Article/s in a Articles Collection). The forget() method accepts 1 argument that could a string||integer||array (of strings or integers)

EXAMPLE:

var articleIdsToRemove = [1, '2', 3];

OR

var articleIdsToRemove = 1; 

var articles = newCollection();

For brevity sake i've excluded the add method for adding Article instances to collection but lets assume we have 10, each with a prop of id

MY CURRENT APPROACH

  1. validate type of value as above i.e. array, str, int, and set all values to an array of ints i.e. ids
  2. then iterate through the array of ids to find an index for Article instance that has prop id and is equal to value id
  3. if found push the index onto indices. One we have all matching indexes then send it Array.prototype.remove to remove multiple items from the collection array. Once that is done then re-sort collection

removed Angular factory wrapper for brevity sake, but assume all of this is in a angular factory called Collection which injects an Article factory that is data model. In summary Collection (articles) contains many Article

    // We set a collections array inside of object to hold all Article instances
    collection = Extendable.prototype.items = [];
    // NOTE add articles method removed, but assume weve added multiple Article's to collection 

    forget = function(id) {
        var ids = [],
            index = null,
            indices = [];
        if (angular.isDefined(id) && !_.isEmpty(id)) {
            ids = _.isArray(id) ? id : isInt(id) ? [Number(id)] : [];
            if (ids.length) {
                _.each(ids, function(id) {
                    index = getIndex('app_id', id);
                    if (index) {
                        indices.push(index)
                    }
                });
                if (indices.length) {
                    collection = collection.remove(indices)
                }
            }
        }
    };
    Extendable.prototype.forget = forget;

    function isInt(n){
        return Number(n) === n && n % 1 === 0;
    }

    function getIndex(prop, value) {
        return _.indexOf(collection, function(d) {
            if (hasProp(d, prop)) {
                return d[prop] == value;
            }
        });
    }

    function hasProp (obj, prop) {
        return Object.prototype.hasOwnProperty.call(obj, prop);
    }

    Array.prototype.remove = function(){
        var args = Array.apply(null, arguments);
        var indices = [];
        for(var i = 0; i < args.length; i++){
            var arg = args[i];
            var index = this.indexOf(arg);
            while(index > -1){
                indices.push(index);
                index = this.indexOf(arg, index + 1);
            }
        }
        indices.sort();
        for(var i = 0; i < indices.length; i++){
            var index = indices[i] - i;
            this.splice(index, 1);
        }
    };
like image 286
Nolan Avatar asked Oct 30 '22 12:10

Nolan


1 Answers

Take a look at this

var forget = function(id) {
  var ids = [];
  if (_.isArray(id)) {
    ids = id;
  } else {
    ids.push(parseInt(id));
  }
  return _.dropWhile(articles, function(n) {
    return _.includes(ids, n.id);
  });
}

Example here: http://jsfiddle.net/hFm7j/226/

like image 63
Dan Avatar answered Nov 08 '22 06:11

Dan