JSON array filter does not apply - javascript

I am trying to filter the data from an array, but it is throwing an error saying
filter() is not function
Here is the code:
var selectedObject = [];
selectedObject= JSON.stringify(formsDataSource.data());
//console.log(selectedObject);
//var filtered = $.grep(selectedObject, function (el) {
// return el.po_order_no = 18;
//});
//console.log((filtered));
if (selectedObject == undefined) {
alert("Undefined");
} else {
var data= selectedObject.filter(function (element) { return element.po_order_no = "18"; })
alert("" + data);
}
I tried many things but it is still throwing an error. Any help?

Few observations :
selectedObject= JSON.stringify(formsDataSource.data());
This statement states that selectedObject is a string. A string does not have a filter() method.
condition inside filter function should be element.po_order_no == "18" instead of element.po_order_no = "18"
Solution :
var selectedObject = [
{
"po_order_no": 18,
"po_order_name": "abc"
},
{
"po_order_no": 19,
"po_order_name": "xyz"
}
];
if (selectedObject == undefined) {
console.log("Undefined");
} else {
var data = selectedObject.filter(element => element.po_order_no == "18")
console.log(data);
}

Related

Grouping by fields after reduce is not working in JavaScript

There is a complex object and based on an array which is given as an input I need to modify its properties. Illustration is shown below. If the "field" is same , add them to "or" array .If its different "field" add them to "and" array along with its "value". I am using Set to get keys from both source and input and using them to group based on its keys. Also whenever there are duplicates .ie., suppose the "filterObj" already has the same (field, value) pair. Be it in "and" or inside "or",Then don't add it in the final object
Sandbox: https://codesandbox.io/s/optimistic-mirzakhani-pogpw-so-dpvis
There is a TestCases file in the sandbox which its needs to pass
let filterObj = {
feature: "test",
filter: {
and: [{ field: "field2" }]
}
};
let obj = [{ field: "field2", value: "3" }];
let all_filters = [];
if (filterObj.filter.and && filterObj.filter.and.hasOwnProperty("or")) {
all_filters = [...filterObj.filter.and.or];
} else if (filterObj.filter.and) {
all_filters = [...filterObj.filter.and];
}
const all_objs = [...obj, ...all_filters];
const uniqKeys = all_objs.reduce(
(acc, curr) => [...new Set([...acc, curr.field])],
[]
);
const updateItems = uniqKeys.map(obj => {
const filter_items = all_objs.filter(item => item.field === obj);
let resultObj = {};
if (filter_items && filter_items.length > 1) {
resultObj.or = [...filter_items];
} else if (filter_items && filter_items.length === 1) {
resultObj = { ...filter_items[0] };
}
return resultObj;
});
var result = { ...filterObj, filter: { and: [...updateItems] } };
console.log(result);
Try it.
I redid the implementation, it happened more universally.
Parses any filters according to your algorithm that it finds.
All test cases are worked.
Sandbox link: https://codesandbox.io/s/optimistic-mirzakhani-pogpw-so-i1u6h
let filterObj = {
feature: "test",
filter: {
and: [
{
field: "field1",
value: "2"
}
]
}
};
let obj = [
{
field: "field1",
value: "2"
},
{
field: "field1",
value: "1"
}
];
var FilterController = function(filter) {
var self = this;
self.filter = filter;
// encapsulated map of objects by fields
var storeMap = {};
// counter of objects
var counter = 0;
var tryPutObjectToMap = function(object) {
if (typeof object === "object") {
// get type for grouping
var objectType = self.getObjectGroupType(object);
if (objectType !== null) {
// cheack have group
if (!storeMap.hasOwnProperty(objectType)) {
storeMap[objectType] = [];
}
var duplicate = storeMap[objectType].find(function(sObject) {
return self.getObjectValue(sObject) === self.getObjectValue(object);
});
// check duplicate
if (duplicate === undefined) {
counter++;
storeMap[objectType].push(object);
} else {
// TODO: Handle duplicates
}
} else {
// TODO: handle incorrect object
}
}
};
// get filter structure from map
var getFilterStructureFromMap = function() {
var result = {};
// check exists root filter and filed if have objects
if (counter > 0) {
result["and"] = [];
}
for (var key in storeMap) {
if (storeMap.hasOwnProperty(key)) {
var array = storeMap[key];
if (array.length > 1) {
result["and"].push({
// clone array
or: array.slice()
});
} else {
result["and"].push(array[0]);
}
}
}
return result;
};
// rewrite and get current filter
// if you need^ create new object for result
self.rewriteAndGetFilter = function() {
self.filter.filter = getFilterStructureFromMap();
return self.filter;
};
// not prototype function for have access to storeMap
self.putObjects = function(objects) {
if (Array.isArray(objects)) {
// recursive push array elements
objects.forEach(element => self.putObjects(element));
// handle array
} else if (typeof objects === "object") {
// handle object
if (objects.hasOwnProperty("and") || objects.hasOwnProperty("or")) {
for (var key in objects) {
//no matter `or` or `and` the same grouping by field
// inner object field
if (objects.hasOwnProperty(key)) {
self.putObjects(objects[key]);
}
}
} else {
// filters props not found, try push to store map
tryPutObjectToMap(objects);
}
} else {
// TODO: Handle errors
}
};
if (self.filter.hasOwnProperty("filter")) {
// put and parse current objects from filter
self.putObjects(self.filter.filter);
}
};
// function for grouping objects.
// for you get filed name from object.
// change if need other ways to compare objects.
FilterController.prototype.getObjectGroupType = function(obj) {
if (typeof obj === "object" && obj.hasOwnProperty("field")) {
return obj.field;
}
return null;
};
// get object value
FilterController.prototype.getObjectValue = function(obj) {
if (typeof obj === "object" && obj.hasOwnProperty("value")) {
return obj.value;
}
return null;
};
var ctrl = new FilterController(filterObj);
ctrl.putObjects(obj);
var totalFilter = ctrl.rewriteAndGetFilter();
console.log(totalFilter);
console.log(JSON.stringify(totalFilter));
EDIT 1
I did not change the logic; I made a function based on it.
let filterObj = {
feature: "test",
filter: {
and: [
{
field: "field1",
value: "2"
}
]
}
};
let obj = [
{
field: "field1",
value: 2
},
{
field: "field1",
value: "1"
}
];
function appendToFilter(filter, inputObjects) {
var storeMap = {};
var counter = 0;
var handlingQueue = [];
// if filter isset the appen to handling queue
if (filter.hasOwnProperty("filter")) {
handlingQueue.push(filter.filter);
}
// append other object to queue
handlingQueue.push(inputObjects);
// get first and remove from queue
var currentObject = handlingQueue.shift();
while (currentObject !== undefined) {
if (Array.isArray(currentObject)) {
currentObject.forEach(element => handlingQueue.push(element));
} else if (typeof currentObject === "object") {
if (currentObject.hasOwnProperty("and") || currentObject.hasOwnProperty("or")) {
for (var key in currentObject) {
if (currentObject.hasOwnProperty(key)) {
handlingQueue.push(currentObject[key]);
}
}
} else {
// TODO: append fild exists check
if (currentObject.field) {
if (!storeMap.hasOwnProperty(currentObject.field)) {
storeMap[currentObject.field] = [];
}
var localValue = currentObject.value;
// check duplicate
if (storeMap[currentObject.field].find(object => object.value === localValue) === undefined) {
counter++;
storeMap[currentObject.field].push(currentObject);
}
}
}
}
currentObject = handlingQueue.shift();
}
// create new filter settings
var newFilter = {};
// check exists root filter and filed if have objects
if (counter > 0) { newFilter["and"] = []; }
for (var storeKey in storeMap) {
if (storeMap.hasOwnProperty(storeKey)) {
var array = storeMap[storeKey];
if (array.length > 1) {
newFilter["and"].push({
// clone array
or: array.slice()
});
} else {
newFilter["and"].push(array[0]);
}
}
}
filter.filter = newFilter;
}
// update filterObj
appendToFilter(filterObj, obj);
console.log(filterObj);
EDIT 2,3 (UPDATED)
With others objects support.
export function appendToFilter(filter, inputObjects) {
var storeMap = {};
var others = [];
var counter = 0;
var handlingQueue = [];
// if filter isset the appen to handling queue
if (filter.hasOwnProperty("filter") && filter.filter.hasOwnProperty("and")) {
handlingQueue.push(filter.filter.and);
}
// append other object to queue
handlingQueue.push(inputObjects);
// get first and remove from queue
var currentObject = handlingQueue.shift();
while (currentObject !== undefined) {
if (Array.isArray(currentObject)) {
currentObject.forEach(element => handlingQueue.push(element));
} else if (typeof currentObject === "object") {
if (
currentObject.hasOwnProperty("and") ||
currentObject.hasOwnProperty("or")
) {
for (var key in currentObject) {
if (currentObject.hasOwnProperty(key)) {
handlingQueue.push(currentObject[key]);
}
}
} else {
// TODO: append fild exists check
if (currentObject.field) {
if (!storeMap.hasOwnProperty(currentObject.field)) {
storeMap[currentObject.field] = [];
}
var localValue = currentObject.value;
// check duplicate
if (
storeMap[currentObject.field].find(
object => object.value === localValue
) === undefined
) {
counter++;
storeMap[currentObject.field].push(currentObject);
}
} else {
// handle others objects^ without field "field"
counter++;
others.push(currentObject);
}
}
}
currentObject = handlingQueue.shift();
}
// create new filter settings
var newFilter = {};
// check exists root filter and filed if have objects
if (counter > 0) {
newFilter["and"] = [];
}
for (var storeKey in storeMap) {
if (storeMap.hasOwnProperty(storeKey)) {
var array = storeMap[storeKey];
if (array.length > 1) {
newFilter["and"].push({
// clone array
or: array.slice()
});
} else {
newFilter["and"].push(array[0]);
}
}
}
// Append others to result filter
others.forEach(other => newFilter["and"].push(other));
filter.filter = newFilter;
}

How to fix my Bookmark local-storage service

My Bookmark Service which stores a result item with JSON structure doesn't work well.
Probably the issue comes from the array that doesn't work with the local storage function.
I've tried to JSON.stringify my items.
var key = 'fud_bookmarks';
var bookmarks = [];
this.addBookmark = function(resultItem) {
var bookmarks = this.getBookmarks();
bookmarks.push(resultItem);
return setBookmarks(bookmarks);
};
this.deleteBookmark = function(resultItem) {
var bookmarks = this.getBookmarks();
var i = bookmarks.indexOf(resultItem);
if (i >= 0) {
bookmarks.splice(i, 1);
console.log(bookmarks)
return setBookmarks(bookmarks);
}
return false;
};
this.getBookmarkCount = function() {
return getBookmarks().length;
};
this.getBookmarks = function() {
var bookmarks = localStorage.getItem(key);
if (!bookmarks) {
bookmarks = [];
}
return bookmarks;
}
function setBookmarks(bookmarks) {
return localStorage.setItem(key, bookmarks);
}
The resulted items look like this.
{
id: "112",
docType: "doctyp117",
title: "Abschließender Bericht über die Arbeit des Kunsts…- September 1944, Exemplar für Tieschowitz, o.D.",
type: "Archivbestand",
description: null,
…
}
$$hashKey: "object:455"
archive: {
id: "24",
title: "Familienarchiv der Grafen Wolff Metternich zur Gracht"
}
right now I get this error in the console =>
bookmarks.push is not a function
at Object.addBookmark (bookmark.js:12)
localStorage store a string values, not an objects.
If you want to store an Array should stringify it.
function setBookmarks(bookmarks) {
return localStorage.setItem(key, JSON.stringify(bookmarks));
}
this.getBookmarks = function () {
var bookmarks = JSON.parse(localStorage.getItem(key));
...
https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
If value in starage will be not a valid JSON JSON.parse method throw an error, so you can use a try catch to avoid errors:
this.getBookmarks = function () {
var bookmarks;
try {
bookmarks = JSON.parse(localStorage.getItem(key));
} catch (e) {
bookmarks = [];
}
...
deleteBookmark should looks like:
this.deleteBookmark = function (resultItem) {
var i = 0;
let bookmarks = this.getBookmarks();
​
for (;i < bookmarks.length - 1;i++) {
if (resultItem.id === bookmarks[i].id) {
break;
}
}
if (i >= 0) {
bookmarks.splice(i, 1);
console.log(bookmarks)
return setBookmarks(bookmarks);
}
return false;
}
Try this: Check if typeof bookmarks is not object then return empty array. As Array is also a special type of object in javascript.
this.getBookmarks = function() {
var bookmarks = localStorage.getItem(key);
if (typeof bookmarks !== "object") {
bookmarks = [];
};
return bookmarks;
};

Check if the property exist in array

The name attribute_name:"position" is very rare and I want to check that if the property exists I want to push it to the new array. However, every time I try to add a condition it gives me errors.
[0].attribute_name inside the for loop is giving me trouble. There may or may not be two arrays inside activity_attributes. But I want to make a call bases on first array, if the itemloop[i].activity_attributes[0].attribute_name push them to new array.
if(res.status == "success") {
var itemloop = res.response.activities;
var social_post_link = [];
for(var i=0; i<itemloop.length; i++){
if(itemloop[i].activity_attributes[0].attribute_name == "position") {
social_post_link.push(itemloop[i].activity_attributes);
}
}
console.log(social_post_link);
}
You can use if('attribute_name' in yourObject) to achieve that.
Demo.
var res = {
status: 'success',
response: {
activities : [
{
activity_attributes: [
{
attribute_name: 'position'
}
]
},
{
activity_attributes: [
{
test: 'test'
}
]
}
]
}
};
if(res.status == "success") {
var itemloop = res.response.activities;
var social_post_link = [];
for(var i=0; i<itemloop.length; i++){
if( 'attribute_name' in itemloop[i].activity_attributes[0]){ //HERE
if(itemloop[i].activity_attributes[0].attribute_name == "position") {
social_post_link.push(itemloop[i].activity_attributes);
}
}
}
console.log(social_post_link);
}
Use should use the hasOwnProperty method
if(itemloop[i].activity_attributes[0].hasOwnProperty('attribute_name') && itemloop[i].activity_attributes[0].attribute_name == "position")
You code should be like
if(res.status == "success") {
var itemloop = res.response.activities;
var social_post_link = [];
for(var i=0; i<itemloop.length; i++){
if(itemloop[i].activity_attributes[0].hasOwnProperty('attribute_name') && itemloop[i].activity_attributes[0].attribute_name == "position") {
social_post_link.push(itemloop[i].activity_attributes);
}
}
console.log(social_post_link);
}
Array.prototype.filter() and Array.prototype.map() can be combined to construct new arrays based on predicated rules such as attribute_name == 'position' and return child values.
See below for a practical example.
if (res.status == 'success') {
const itemloop = res.response.activities
const social_post_link = itemloop.filter(x => x.attribute_name == 'position').map(x => x.activity_attributes)
console.log(social_post_link)
}
instead of activity_attributes[0].attribute_name ,try using activity_attributes[0]['attribute_name'] == 'position'

AngularJs - check if value exists in array object

var SelectedOptionId = 957;
$scope.array = [{"957":"1269"},{"958":"1265"},{"956":"1259"},{"957":"1269"},{"947":"1267"}]
Is there a way of checking if a value exists in an that kind of array objects. I am using Angular and underscore.
I have tried all this -
if ($scope.array.indexOf(SelectedOptionId) === -1) {console.log('already exists')}
and
console.log($scope.array.hasOwnProperty(SelectedOptionId)); //returns false
and
console.log(_.has($scope.array, SelectedOptionId)); //returns false
You could use Array#some and check with in operator.
exists = $scope.array.some(function (o) {
return SelectedOptionId in o;
});
Check this
function checkExists (type) {
return $scope.array.some(function (obj) {
return obj === type;
}
}
var chkval=checkExists("your value")
Try this:
if($scope.array[SelectedOptionId] || _.includes(_.values($scope.array, SelectedOptionId))) { }
That should cover both a key and a value.
let selectedOptionId = "957";
let array = [{"957":"1269"},{"958":"1265"},{"956":"1259"},{"957":"1269"},{"947":"1267"}];
let filtered = array.filter(function(element){
return Object.keys(element)[0] === selectedOptionId;
});
console.log(filtered);
console.log(_.some($scope.array, function(o) { return _.has(o, "957"); }));
using underscore
You can use filter for this. The following code should return you output array with matching results, if it exists, otherwise it will return an empty array :
var array = [{"957":"1269"},{"958":"1265"},{"956":"1259"},{"957":"1269"},{"947":"1267"}];
var SelectedOptionId = 957;
var result = array.filter(
function(item) {return item[SelectedOptionId]}
)
console.log(result);
For your input it returns:
[ { '957': '1269' }, { '957': '1269' } ]
You can do it using the in operator or the hasOwnProperty function, to check for the existence of a key in an object inside the given array.
The way you've tried using hasOwnProperty function didn't work because you were checking it directly on the array instead of checking against the items in the array.
Check the below code snippet.
angular
.module('demo', [])
.controller('HomeController', DefaultController);
function DefaultController() {
var vm = this;
vm.items = [{
"957": "1269"
}, {
"958": "1265"
}, {
"956": "1259"
}, {
"957": "1269"
}, {
"947": "1267"
}];
var key = '957';
var isExists = keyExists(key, vm.items);
console.log('is ' + key + ' exists: ' + isExists);
function keyExists(key, items) {
for (var i = 0; i < items.length; i++) {
// if (key in items[i]) {
if (items[i].hasOwnProperty(key)) {
return true;
}
}
return false;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="HomeController as home">
{{home.items | json}}
</div>
</div>
Different ways to do this :
Using Object hasOwnProperty() method.
Working demo :
var SelectedOptionId = 957;
var arrayObj = [{"957":"1269"},{"958":"1265"},{"956":"1259"},{"957":"1269"},{"947":"1267"}];
function checkOption(key) {
for(var i in arrayObj) {
if(arrayObj[i].hasOwnProperty(key) == true) {
return key+" exists.";
} else {
return key+" Not exists.";
}
}
};
console.log(checkOption(SelectedOptionId)); // 957 exists.
using Array filter() method.
Working demo :
var SelectedOptionId = 957;
var arrayObj = [{"957":"1269"},{"958":"1265"},{"956":"1259"},{"957":"1269"},{"947":"1267"}];
var result = arrayObj.filter(function(elem) {
return elem[SelectedOptionId]
});
if(result == '') {
console.log(SelectedOptionId+" not exists.");
} else {
console.log(SelectedOptionId+" exists.");
}
using Array some() method as suggested by Nina Scholz.
Working demo :
var SelectedOptionId = 957;
var arrayObj = [{"957":"1269"},{"958":"1265"},{"956":"1259"},{"957":"1269"},{"947":"1267"}];
var result = arrayObj.some(function (o) {
return SelectedOptionId in o;
});
if(result == '') {
console.log(SelectedOptionId+" not exists.");
} else {
console.log(SelectedOptionId+" exists.");
}

Find an element in an array recursively

I have an array of objects. Every object in the array has an id and an item property that is an array containing other object. I need to be able to find an element in an array by id. Here is a sample of what I have done so far, but the recursive function is always returning undefined.
How can I quit the function and return the item when I have called the function recursively several times?
$(function () {
var treeDataSource = [{
id: 1,
Name: "Test1",
items: [{
id: 2,
Name: "Test2",
items: [{
id: 3,
Name: "Test3"
}]
}]
}];
var getSubMenuItem = function (subMenuItems, id) {
if (subMenuItems && subMenuItems.length > 0) {
for (var i = 0; i < subMenuItems.length; i++) {
var item;
if (subMenuItems[i].Id == id) {
item = subMenuItems[i];
return item;
};
getSubMenuItem(subMenuItems[i].items, id);
};
};
};
var searchedItem = getSubMenuItem(treeDataSource, 3);
alert(searchedItem.id);
});
jsFiddle
You should replace
getSubMenuItem(subMenuItems[i].items, id);
with
var found = getSubMenuItem(subMenuItems[i].items, id);
if (found) return found;
in order to return the element when it is found.
And be careful with the name of the properties, javascript is case sensitive, so you must also replace
if (subMenuItems[i].Id == id) {
with
if (subMenuItems[i].id == id) {
Demonstration
Final (cleaned) code :
var getSubMenuItem = function (subMenuItems, id) {
if (subMenuItems) {
for (var i = 0; i < subMenuItems.length; i++) {
if (subMenuItems[i].id == id) {
return subMenuItems[i];
}
var found = getSubMenuItem(subMenuItems[i].items, id);
if (found) return found;
}
}
};
I know its late but here is a more generic approach
Array.prototype.findRecursive = function(predicate, childrenPropertyName){
if(!childrenPropertyName){
throw "findRecursive requires parameter `childrenPropertyName`";
}
let array = [];
array = this;
let initialFind = array.find(predicate);
let elementsWithChildren = array.filter(x=>x[childrenPropertyName]);
if(initialFind){
return initialFind;
}else if(elementsWithChildren.length){
let childElements = [];
elementsWithChildren.forEach(x=>{
childElements.push(...x[childrenPropertyName]);
});
return childElements.findRecursive(predicate, childrenPropertyName);
}else{
return undefined;
}
}
to use it:
var array = [<lets say an array of students who has their own students>];
var joe = array.findRecursive(x=>x.Name=="Joe", "students");
and if you want filter instead of find
Array.prototype.filterRecursive = function(predicate, childProperty){
let filterResults = [];
let filterAndPushResults = (arrayToFilter)=>{
let elementsWithChildren = arrayToFilter.filter(x=>x[childProperty]);
let filtered = arrayToFilter.filter(predicate);
filterResults.push(...filtered);
if(elementsWithChildren.length){
let childElements = [];
elementsWithChildren.forEach(x=>{
childElements.push(...x[childProperty]);
});
filterAndPushResults(childElements);
}
};
filterAndPushResults(this);
return filterResults;
}

Categories