1

I have a list with that contains a list of objects. Each object has 4 properties on it. There is a checkbox list with the unique values of two of the properties, this helps build my filter array.

the Filter might end up looking like this:

[
    {
        prop: 'username',
        val: ['max', 'sam']
     },
     {
        prop: 'color',
        val: ['blue', 'green']
     }
]

The list of objects would look something like this:

[
    {
        username: 'sam',
        color: 'blue'
    },
    {
        username: 'jimmy',
        color: 'blue'
    },
    {
        username: 'sam',
        color: 'black'
    },
    {
        username: 'max',
        color: 'green'
    },
    {
        username: 'max',
        color: 'blue'
    }
]

The Desired Result

[
    {
        username: 'sam',
        color: 'blue'
    },
    {
        username: 'max',
        color: 'green'
    },
    {
        username: 'max',
        color: 'blue'
    }
]

I feel like I'm going down a never ending forEach rabbit hole. I'm guessing I need some sort of recursion. Currently here is what I have:

var temporary = scope.transactions;

function getFilteredTransactions() {
    var filter = deviceFilterService.get();

    if (filter.length > 0) {
        var temp2 = [];
        angular.forEach(filter, function (fil) {
            //object
            angular.forEach(fil.val, function (filterValue) {
                //list on each object
                angular.forEach(temporary, function (transaction) {                                 
                    if (transaction[fil.prop] === filterValue) {
                        if (temp2.indexOf(transaction) === -1) {
                            temp2.push(transaction);
                        }
                    }
                });

                temporary = temp2;
            });
        });

        $log.debug(temporary);
        scope.transactions = temporary;
    } else {
        initialize();
    }
}

This is starting to work, the second time it goes through the property for color it ends up just wanting to add the exact same transaction to the temp2 array. There has to be a better way to set this up, possibly through recursion.

3
  • This is not valid js: {'max', 'sam'} Update your question with a valid desired result. Also, change username to name, otherwise there's no way to match up the two. Commented May 28, 2015 at 23:50
  • (!temp2.indexOf(transaction)) should be (!temp2.indexOf(transaction) < 0) ? Commented May 29, 2015 at 0:08
  • Made a fiddle of what I think you're looking for - but didn't use your existing code: jsfiddle.net/Lz32hka5/1 Commented May 29, 2015 at 0:11

4 Answers 4

1

If you convert the format of the first list to a dictionary, i think if should get easier.

var dict = {};
angular.forEach(source1, function(ob){
  dict[ob.prop] = ob.val;
});


function getFiltered(ob){
  for(var prop in ob){
    if(dict[prop] && dict[prop].indexOf(ob[prop]) === -1){
      return false;
    }
  }
 return true;
};

and just call it as:

var temporary = scope.transactions.filter(getFiltered);

Demo


Basically the first part converts:

[
    {
        prop: 'username',
        val: ['max', 'sam']
     },
     {
        prop: 'color',
        val: ['blue', 'green']
     }
];

to:

{ 
  username:['max', 'sam'],
  color:['blue', 'green']
 }

so that it makes the look up much easier.

Sign up to request clarification or add additional context in comments.

7 Comments

I like this route a lot, very little code. My implementation is slightly different and keep getting errors of undefined, writing up a plunkr now
@JonHarding Sure, i just went with data in the question, probably may have to add some null checks
yes, the data will have properties that won't be filtered
@JonHarding alright please show me a plunker with more info...and replica... probably i did not get your actual expectation fully
@JonHarding Here it is is this what you expected
|
0

You might want to change the variable names here for clarity, but this will do what you're asking for:

        var values = {};
        angular.forEach(startingData, function(rawData) {
            angular.forEach(rawData, function(value, key) {
                if (angular.isUndefined(values[key])) {
                    values[key] = [];
                }
                if (values[key].indexOf(value) === -1) {
                    values[key].push(value);
                }
            })
        });
        var result = [];
        angular.forEach(values, function(value, key) {
            result.push({prop: key, val: value})
        });

2 Comments

this creates an object the value being an arrray of strings, and the property being the key. I need to filter the list like I mentioned above. This would be a better way to create the filter though
I misread the question. I took the "filtered" part above as the desired result. ignore this answer :-)
0

You can simply iterate each key of the data the needs filtering, find the appropriate filter per that key, and check the value against the filter values:

$scope.transactions = $scope.transactions.filter(isItemValidFilter);

function isItemValidFilter(item) {
    var filters = deviceFilterService.get();

    //For each property in the data, get the correct filter from the list of filters
    var totalConditions = Object.keys(item).length;
    var correctConditions = 0;

    for (var filterKey in item) {
        var correctFilters = filters.filter(function(dataFilter) {
            return dataFilter.prop == filterKey
        });

        if (correctFilters.length) {
            //Ill assume only 1 filter, so just use the 0 index
            var correctFilter = correctFilters[0];
            var conditions = correctFilter.val;

            if (conditions && conditions.length) {
                //check the values!
                if (conditions.indexOf(item[filterKey]) > -1) {
                    correctConditions++;
                }
            }
        }

    }
    return correctConditions === totalConditions;
}

Demo: http://jsfiddle.net/Lz32hka5/1/

Comments

0

Try:

var temp2 = [], matched;

angular.forEach(temporary, function(item){
    matched = true;
    angular.forEach(Object.keys(item), function(key){
        angular.forEach(filter, function(filter){
            filter.prop == key && filter.val.indexOf(item[key]) == -1 && (matched = false);
        });
    });
    matched && temp2.push(item);
});

console.log(temp2)

temporary is the list of objects, filter: your filters

Demo: http://jsfiddle.net/wZVanG/7wnae850/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.