Underscore JS to retrieve object by ID - angularjs

I have a input where I want to find an object by ID. At the moment I am returning both objects but what I want is if I search '01' I would just return the first object. I have tried underscore _.map to do this but it did not give the result I am after.
var getById = function() {
var deferred = Q.defer(),
result;
result = items;
if (!result) {
deferred.reject('item not found');
} else {
deferred.resolve(result);
}
return deferred.promise;
};
JSON:
[{
"id": "01",
"name": "test1",
"orderItems": [
{
"productNumber": "TESTa",
"quantity": 2,
},
{
"productNumber": "TESTb",
"quantity": 4,
},
{
"productNumber": "TESTc",
"quantity": 6,
}
]
},{
"id": "02",
"name": "test2",
"orderItems": [
{
"productNumber": "TESTe",
"quantity": 2,
},
{
"productNumber": "TESTf",
"quantity": 7,
},
{
"productNumber": "TESTg",
"quantity": 6,
}
]
}]

You can use _.filter()
Looks through each value in the list, returning an array of all the values that pass a truth test (predicate).
result = _.filter(items, function(item){
return item.id == '01';
});
Or, _.findWhere
Looks through the list and returns the first value that matches all of the key-value pairs listed in properties.
result = _.findWhere(items, {id : '01'});

var result = _.find(myItems, function(item) { return item.id === '01'; }

If you find single item which matches the conditions, use _.find()
It looks through each value in the list, returning the first one that
passes a truth test
var _exist = _.find(_items, function (item) {
return item.id == your_id;
});
If you find all items which matches the conditions, use _.filter()
It looks through each value in the list, returning an array of all the
values that pass a truth test
var _exist = _.filter(_items, function (item) {
return item.id == your_id;
});
Catch the complete documentation here:
http://underscorejs.org/

Related

Convert Flat JSON string into hierarchical using Parent ID

I am implementing a Mat-Tree using Angular Material. I have a flat JSON string like:
"Entity": [
{
"ID": 1,
"NAME": "Reports",
"PARENTID": "0",
"ISACTIVE": "Y",
"CREATIONDATE": "2020-03-31T15:08:11",
"UPDATIONDATE": "2020-03-31T15:08:11",
"CREATEDBY": 596241,
"UPDATEDBY": 596241
},
{
"ID": 2,
"NAME": "TMS - Reports",
"PARENTID": 1,
"ISACTIVE": "Y",
"CREATIONDATE": "2020-03-31T15:08:38",
"UPDATIONDATE": "2020-03-31T15:08:38",
"CREATEDBY": 596241,
"UPDATEDBY": 596241
},
{
"ID": 3,
"NAME": "TMS - Beneficiary ",
"PARENTID": 2,
"ISACTIVE": "Y",
"CREATIONDATE": "2020-03-31T15:09:34",
"UPDATIONDATE": "2020-03-31T15:09:34",
"CREATEDBY": 596241,
"UPDATEDBY": 596241
}
]
And I need to convert it into Key-value pairs based on their Parent ID. Something like:
{
Reports:
{
'Type 1 Reports': ['Beneficiary Reports', 'Some Other Report'],
'Type 2 Reports': null //No Children,
},
Some Other Menu Items: {
'My Parent Node': null,
'Some Other Menu Node': ['Child 1', 'Child 2']
}
}
So far, I am able to use this code to convert it into a parent-child hierarchy, but It has pushed all children into Items array which I cannot iterate with Mat-Tree. I need to get rid of the Items and have something like a key-value pair as the one I mentioned above:
generateTreeData(menuResponse)
{
var map = {};
for(var i = 0; i < menuResponse.length; i++){
var obj = menuResponse[i];
var parent = '';
obj.items= [];
map[obj.ID] = obj;
if(obj.PARENTID == "0")
{
parent = '-';
}
else
{
parent = obj.PARENTID;
}
if(!map[parent]){
//Means Parent doesnt exist i.e. node Itself is parent node
map[parent] = {
items: []
};
}
map[parent].items.push(obj);
}
return map['-'].items;
}
Problem:
The code puts children nodes in Items array. I need to get rid of the Items array and place it in key-value pairs like the one I mentioned above. How do I just extract the "NAME" and Items out of this JSON array and make a Key-Value pair? Something like the one I mentioned above?
The expected output structure doesn't seem right. What if there is a child for 'Beneficiary Reports' node.
The output structure for the input provided in the question should be like:
{
"Reports":[
{
"TMS - Reports":[
{
"TMS - Beneficiary ":[]
}
]
}
]
}
Check the following fiddle: https://jsfiddle.net/abby_7700/apkgeo1d/3/
var data = [];//your response goes here
var result = {};
var root = data.find(x => x.PARENTID == 0);
result[root.NAME] = [];
findAndAddChildren(root.ID, result[root.NAME]);
console.log(JSON.stringify(result));
function findAndAddChildren(parentID, collection) {
var rootChildren = data.filter(x => x.PARENTID == parentID);
for(var i = 0; i < rootChildren.length; i++) {
var child = rootChildren[i];
var temp = {};
temp[child.NAME] = [];
collection.push(temp);
findAndAddChildren(child.ID, temp[child.NAME]);
}
}

JavaScript (Node.js) - JSON recursion extracting objects to array with order (faltten)

I have a JSON config file as follows:
var conf = [
{
"value": "baz",
"threshold": 20,
"other": 123
},
{
"value": "mo",
"other": 456,
"child": {
"value": "foo",
"other": 789,
"child": {
"value": "larry",
"other": 123
}
}
}
];
I have a requirement to extract each of the objects and persist them together in order if they have child objects. For example, object 1 (baz) is stand alone. Object 2 (mo) will have two child objects. These 3 as a set must be extracted together.
There is no limit to the number of child objects.
Im attempting to persist each object using an array to maintain the order. So the required output would look like:
[[{"value":"baz","threshold":20,"other":123}],
[[{"value":"mo","other":456,"child":{"value":"foo","other":789,"child":{"value":"larry","other":123}}}],
[{"value":"foo","other":789,"child":{"value":"larry","other":123}}],
[{"value":"larry","other":123}]]]
A final requirement is to actually remove the child values from the parents so the output can actually be like:
[
[{"value":"baz","threshold":20,"other":123}],
[
[{"value":"mo","other":456}],
[{"value":"foo","other":789}],
[{"value":"larry","other":123}]
]
]
Ive been hung up on this for hours with little progress. I know I need to create a recursive function, push each node to an array, and then check for child object and repeat.
Heres what I have so far. My thinking is if I can take the array id each task is being pushed to (using a loop id), perhaps I can map that when the function is called again.
Appreciate any guidance.
var execSets = [];
function parser(tasks){
// an ordered array of task execution
for (let eachTask in tasks) {
var taskSet = [];
console.log("====================================");
console.log(tasks[eachTask]);
if(!tasks[eachTask].child && typeof(tasks[eachTask]) === 'object'){
console.log(tasks[eachTask]);
taskSet.push(tasks[eachTask]);
execSets.push(taskSet);
}
if(tasks[eachTask].child){
let childAlias = tasks[eachTask].child;
delete tasks[eachTask].child;
taskSet.push(tasks[eachTask]);
execSets.push(taskSet);
parser(childAlias);
}
}
}
The npm registry is your friend; try 'npm search flat,
There are a few modules that can help flatten a json object. For example https://www.npmjs.com/package/flat
You could do it using recursion. Here is my suggestion:
var conf = [
{
"value": "baz",
"threshold": 20,
"other": 123
},
{
"value": "mo",
"other": 456,
"child": {
"value": "foo",
"other": 789,
"child": {
"value": "larry",
"other": 123
}
}
}
];
function getFlattenedObject(object){
var response = [];
flatten(object, response, 0);
return response;
}
function flatten(object, array, index){
if(!array[index]){
array.push([]);
}
array[index].push(object);
if(object.child){
flatten(object.child, array, index + 1);
object.child = undefined;
}
}
//Logs for comparison
console.dir(conf)
console.dir(getFlattenedObject(conf));
The result structure you are looking for wasn't "intuitive" and hence the solution has gotten a little ugly, but here is how you could use object-scan to answer your question
// const objectScan = require('object-scan');
const data = [{"value":"baz","threshold":20,"other":123},{"value":"mo","other":456,"child":{"value":"foo","other":789,"child":{"value":"larry","other":123}}}]
const fn = (haystack) => objectScan(['[*]', '**.child'], {
filterFn: ({
key: [id, ...p],
value: { child, ...node },
context
}) => {
if (!(id in context)) {
context[id] = [];
}
context[id].push(child || p.length !== 0 ? [node] : node);
}
})(haystack, []);
console.log(fn(data));
// => [ [ { value: 'baz', threshold: 20, other: 123 } ], [ [ { value: 'larry', other: 123 } ], [ { value: 'foo', other: 789 } ], [ { value: 'mo', other: 456 } ] ] ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.7.1"></script>
Disclaimer: I'm the author of object-scan

How to automatically update connected parts of json with angularjs

I have next json structure:
{
"items": [
{"name":"item1"},
{"name":"item2"},
{"name": "item3"}
],
"groups": [{
"name": "group1",
"items": ["item1", "item3"]
},
{
"name": "group2",
"items": ["item2", "item3"]
},
{
"name": "group3",
"items": ["item1", "item2"]
}]
}
As you can see in my groups I have names of the items.
Is there a way in angularjs to automatically update strings in group > items, when the name of the particular item change. (Is there a way to connect particular parts of the json model?)
Thank you.
You can set up a deep $watch for each item in the item array. When the item changes, iterate over the group items, and replace the old name with the new name:
angular.forEach($scope.model.items, function (item) {
$scope.$watch(function () { return item; }, function (newVal, oldVal) {
angular.forEach($scope.model.groups, function (group) {
var items = group.items;
var itemIndex = items.indexOf(oldVal.name);
if (itemIndex >= 0) {
items[itemIndex] = newVal.name;
}
});
}, true);
});
Demo Fiddle

How to get a count of a items within a collection that match a specific criteria?

I have a collection like so:
{ "items": [
{
"id": "123",
"meta": {
"activity": 2
}
},
{
"id": "13423",
"meta": {
"activity": 4
}
}
]}
Given the collection, how can I get the collection's total activity? In the case above the result would be 6.
I'm using backbone and underscore.
You're using underscore.js, so you have some good tools at your disposal. Look at _.map() to get started.
var flatArray = _.map(collection.items, function(x){return x.meta.activity;});
// should return: [2,4]
Then you can use _.reduce() to turn this into a single value.
var total = _.reduce(flatArray, function(memo, num) {return memo + num;}, 0);
// should return: 6
There's lots of other great tools in underscore.js, it's worth a look to see if anything else would work for you too.
In underscore you can use the reduce function which will reduce a list of values into a single value using the given iterator function.
var myCollection = { "items": [
{
"id": "123",
"meta": {
"activity": 2
}
},
{
"id": "13423",
"meta": {
"activity": 4
}
}
]};
var totalActivity = _.reduce(myCollection.items, function(memo, item){ return memo + item.meta.activity; }, 0);

$filter with custom function in angular

How I can create a $filter with custom function to determining if match ?
This is a json sample with structure:
$scope.routes =[
{
"id": 0,
"name": "Rosa Barnes",
"origin": [
{
"address": [
{
"locality": "Madrid",
"country": "ES"
}
]
}
]
},
{
"id": 1,
"name": "Wright Montoya",
"origin": [
{
"address": [
{
"locality": "London",
"country": "UK"
}
]
}
]
},
{
"id": 2,
"name": "Pearson Johns",
"origin": [
{
"address": [
{
"locality": "London",
"country": "UK"
}
]
}
]
}
];
I want a $filter that passing one country, match in origin.address.country , is possible?
I proved this code but not works:
$scope.routesToShow = $filter('filter')($scope.routes, {origin.address.country: "UK"});
Here there are a demo:
http://jsfiddle.net/86U29/43/
Thanks
What you need is a custom filter. It also looks like you might need to tweak your data structure too.
Take a look at this:
app.filter('CustomFilter', function () {
function parseString(propertyString) {
return propertyString.split(".");
}
function getValue(element, propertyArray) {
var value = element;
propertyArray.forEach(function (property) {
value = value[property];
});
return value;
}
return function (input, propertyString, target) {
var properties = parseString(propertyString);
return input.filter(function (item) {
return getValue(item, properties) == target;
});
}
});
You could use this filter, like this:
$scope.routesToShow = $filter('CustomFilter')($scope.routes, 'origin.address.country', 'UK');
Here is an updated jsfiddle (notice the updated data structure): http://jsfiddle.net/moderndegree/86U29/44/
You can find more information on creating custom filters here:
https://docs.angularjs.org/guide/filter#creating-custom-filters
Simply.
var filter = function(obj){
return obj.origin[0].address[0].country === 'UK';
}
$scope.routesToShow = $filter('filter')($scope.routes, filter);

Resources