Jquery how to find an Object by attribute in an Array

JqueryCollectionsFilterTraversal

Jquery Problem Overview


Given I have an array of "purpose" objects:

//array of purpose objects:
var purposeObjects = [
    {purpose: "daily"},
    {purpose: "weekly"},
    {purpose: "monthly"}
];

(for simplicity i am omitting other attributes)

Now I want to have a method that returns a specific one of the objects if a matching purpose name is found.

This is not working:

function findPurpose(purposeName){
    return $.grep(purposeObjects, function(){
      return this.purpose == purposeName;
    });
};

findPurpose("daily");

but it actually returns an empty array:

[]

I am using JQuery 1.5.2. I have also tried with $.each() but with no luck. Apparently, most JQuery methods are designed for usage with DOM elements (such as filter().

Any ideas on how to achieve this?

Jquery Solutions


Solution 1 - Jquery

No need for jQuery.

JavaScript arrays have a find method, so you can achieve that in one line:

array.find((o) => { return o[propertyName] === propertyValue })

Example


const purposeObjects = [
    {purpose: "daily"},
    {purpose: "weekly"},
    {purpose: "monthly"}
];

purposeObjects.find((o) => { return o["purpose"] === "weekly" })      

// output -> {purpose: "weekly"}

If you need IE compatibility, import this polyfill in your code.

Solution 2 - Jquery

you should pass reference on item in grep function:

function findPurpose(purposeName){
    return $.grep(purposeObjects, function(item){
      return item.purpose == purposeName;
    });
};

Example

Solution 3 - Jquery

I personally use a more generic function that works for any property of any array:

function lookup(array, prop, value) {
	for (var i = 0, len = array.length; i < len; i++)
		if (array[i] && array[i][prop] === value) return array[i];
}

You just call it like this:

lookup(purposeObjects, "purpose", "daily");

Solution 4 - Jquery

The error was that you cannot use this in the grep, but you must use a reference to the element. This works:

function findPurpose(purposeName){
    return $.grep(purposeObjects, function(n, i){
      return n.purpose == purposeName;
    });
};

findPurpose("daily");

returns:

[Object { purpose="daily"}]

Solution 5 - Jquery

Use the Underscore.js findWhere function (http://underscorejs.org/#findWhere):

var purposeObjects = [
    {purpose: "daily"},
    {purpose: "weekly"},
    {purpose: "monthly"}
];

var daily = _.findWhere(purposeObjects, {purpose: 'daily'});

daily would equal:

{"purpose":"daily"}

Here's a fiddle: http://jsfiddle.net/spencerw/oqbgc21x/

To return more than one (if you had more in your array) you could use _.where(...)

Solution 6 - Jquery

Best, Fastest way is

function arrayLookup(array, prop, val) {
    for (var i = 0, len = array.length; i < len; i++) {
        if (array[i].hasOwnProperty(prop) && array[i][prop] === val) {
            return array[i];
        }
    }
    return null;
}

Solution 7 - Jquery

If your array is actually a set of JQuery objects, what about simply using the .filter() method ?

purposeObjects.filter('[purpose="daily"]')

Solution 8 - Jquery

One more solution:

function firstOrNull(array, expr) {
  for (var i = 0; i < array.length; i++) {
    if (expr(array[i]))
      return array[i];
    }
  return null;
}

Using: firstOrNull([{ a: 1, b: 2 }, { a: 3, b: 3 }], function(item) { return item.a === 3; });

This function don't executes for each element from the array (it's valuable for large arrays)

Solution 9 - Jquery

I have created a util service for my angular application. It have two function which use very often.

For example you have object.

First getting value from object recursively without throwing undefined error.

{prop: { nestedProp1: {nestedProp2: somevalue}}}; get nestedProp2 2 without undefined checks.

Second filter array on basis

[{prop: { nestedProp1: {nestedProp2: somevalue1}}}, {prop: { nestedProp1: {nestedProp2: somevalue2}}}];

Find object from array with nestedProp2=somevalue2

app.service('UtilService', function(httpService) {
this.mapStringKeyVal = function(map, field) {
	var lastIdentifiedVal = null;
	var parentVal = map;
	field.split('.').forEach(function(val){
		if(parentVal[val]){
			lastIdentifiedVal = parentVal[val]; 
			parentVal = parentVal[val]; 
		}
	});
	return lastIdentifiedVal;
}


this.arrayPropFilter = function(array, field,value) {
	var lastIdentifiedVal = null;
	var mapStringKeyVal = this.mapStringKeyVal;
	array.forEach(function(arrayItem){
		var valueFound = mapStringKeyVal(arrayItem,field);
		if(!lastIdentifiedVal  && valueFound && valueFound==value){
			lastIdentifiedVal = arrayItem;
		}
	});
	return lastIdentifiedVal;
}});

For solution for current question. inject UtilService and call,

UtilService.arrayPropFilter(purposeArray,'purpose','daily');

Or more advanced

UtilService.arrayPropFilter(purposeArray,'purpose.nestedProp1.nestedProp2','daily');

Solution 10 - Jquery

Javascript has a function just for that: Array.prototype.find. As example

function isBigEnough(element) {
  return element >= 15;
}

[12, 5, 8, 130, 44].find(isBigEnough); // 130

It not difficult to extends the callback to a function. However this is not compatible with IE (and partially with Edge). For a full list look at the Browser Compatibility

Solution 11 - Jquery

copied from polyfill Array.prototype.find code of Array.find, and added the array as first parameter.

you can pass the search term as predicate function

// Example
var listOfObjects = [{key: "1", value: "one"}, {key: "2", value: "two"}]
var result = findInArray(listOfObjects, function(element) {
  return element.key == "1";
});
console.log(result);

// the function you want
function findInArray(listOfObjects, predicate) {
      if (listOfObjects == null) {
        throw new TypeError('listOfObjects is null or not defined');
      }

      var o = Object(listOfObjects);

      var len = o.length >>> 0;

      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }

      var thisArg = arguments[1];

      var k = 0;

      while (k < len) {
        var kValue = o[k];
        if (predicate.call(thisArg, kValue, k, o)) {
          return kValue;
        }
        k++;
      }

      return undefined;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJesper R&#248;nn-JensenView Question on Stackoverflow
Solution 1 - JqueryLuca FagioliView Answer on Stackoverflow
Solution 2 - JqueryAndreiView Answer on Stackoverflow
Solution 3 - JqueryJohannView Answer on Stackoverflow
Solution 4 - JqueryJesper Rønn-JensenView Answer on Stackoverflow
Solution 5 - JqueryjbobbinsView Answer on Stackoverflow
Solution 6 - JqueryKalimView Answer on Stackoverflow
Solution 7 - JqueryDouglasView Answer on Stackoverflow
Solution 8 - JqueryfeeeperView Answer on Stackoverflow
Solution 9 - Jquerysanjay patelView Answer on Stackoverflow
Solution 10 - Jqueryuser2688838View Answer on Stackoverflow
Solution 11 - JqueryAbou-EmishView Answer on Stackoverflow