ng-repeat with nested arrays - javascript

I receive the below data from my REST API
[
{
// restaurant details
},
"city": {}, // city details
"location": {}, // location details
"menu_categories": [
{
// menu_categories details
"menu_items": [
{
// menu_items details
"menu_modifier_groups": [
{
// menu_modifier_groups details
"menu_modifier_items": []
}
]
}
]
}
]
}
]
In this data, I'm fetching a single restaurant with its menu_categories that then has a child menu_items which then has a child menu_modifier_groups which then has a child menu_modifier_item.
As you can see I have arrays nested within each other.
I want to use ng-repeat to group menu_items under menu_categories. something like below;
menu_category 1
menu_item 1
menu_item 2
menu_category 2
menu_item 3
menu_item 4
Also how can I use ng-repeat on just one for the array? I have the data assigned to $scope.restuarant
Any guidance appreciated

You can try this (instead of title you can use whatever property you have set):
<ul>
<li data-ng-repeat="category in restaurant.menu_categories">
{{ category.title }}
<ul data-ng-if="category.menu_items">
<li data-ng-repeat="item in category.menu_items">{{ item.title }}</li>
</ul>
</li>
</ul>

You can use a tree view to display the data
Take a look at this : http://ngmodules.org/modules/angular.treeview
or this link https://github.com/eu81273/angular.treeview ( it the same )
it take for example this data :
$scope.treedata =
[
{ "label" : "User", "id" : "role1", "children" : [
{ "label" : "subUser1", "id" : "role11", "children" : [] },
{ "label" : "subUser2", "id" : "role12", "children" : [
{ "label" : "subUser2-1", "id" : "role121", "children" : [
{ "label" : "subUser2-1-1", "id" : "role1211", "children" : [] },
{ "label" : "subUser2-1-2", "id" : "role1212", "children" : [] }
]}
]}
]},
{ "label" : "Admin", "id" : "role2", "children" : [] },
{ "label" : "Guest", "id" : "role3", "children" : [] }
];
You can easly adapt the rest api data to this

Working plunker - http://plnkr.co/edit/fjDsJbmd7DIlBK3xrdyu.
To group menu_items under menu_categories using ng-repeat
<ul ng-repeat="(key, value) in restaurant" ng-init="outerIndex = $index">
menu_category {{$index + 1}}
<li ng-init="innerIndex = $index" ng-repeat="menu_cat in value.menu_categories">
menu_item {{($parent.$index*value.menu_categories.length)+($index+1)}}
</li>
</ul>
And the output would be:
menu_category 1
- menu_item 1
- menu_item 2
menu_category 2
- menu_item 3
- menu_item 4
menu_category 3
- menu_item 5
- menu_item 6
Hope this answered your question.

Related

How to find data on MongoDB by passing part of array objects

I tried to create an API for filtering the products by sending an array of objects as filters.
this is my Product schema:
const mongoose = require("mongoose");
const { s, rs, rn, rref, ref } = require("../utils/mongo");
let schema = new mongoose.Schema(
{
user: rref("user"),
name: rs,
description: s,
images: [s],
price: rn,
category: ref("category"),
filters: [
{
parent: ref("filter"),
value: s,
name: s,
},
],
subFilter: [
{
parent: s,
value: s,
title: s,
},
],
},
{ timestamps: true }
);
module.exports = mongoose.model("product", schema);
and this one is what I want to send as body to the API
{
category: '62445c3d922d127512867245'
filters: [
{ name: 'filter name 1', value: '62445c3d922d127512861236' },
{ name: 'filter name 2', value: '62445c3d922d127512861458' },
.....
]
}
as you see I want to filter my products based on category Id and an array of filter objects. I tried to write this query but it return an empty array.
this is my query:
filter: async (req, res) => {
try {
const { category, filters } = req.body;
const products = await Product.find({
category,
filters: {
$in: filters,
},
});
res.status(200).json(products);
} catch (err) {
res.status(500).json(err);
}
},
what stored on db
{
"_id" : ObjectId("62643acf19636d7db1804cb3"),
"images" : [
"image-1650735823476۸.jpg"
],
"user" : ObjectId("622606af0f40cb8ea37383dc"),
"name" : "شیر توپی 2 اینچ کلاس 150 پیشگام",
"description" : " برند پیشگام با مدارک و تاییدیه ",
"price" : NumberInt(5000000),
"category" : ObjectId("62445c4d922d127512867246"),
"filters" : [
{
"_id" : ObjectId("62643acf19636d7db1804cb4"),
"parent" : ObjectId("6264307f19636d7db1804b77"),
"value" : "626430bb19636d7db1804b78",
"name" : "Valve Type"
},
{
"_id" : ObjectId("62643acf19636d7db1804cb5"),
"parent" : ObjectId("6264319819636d7db1804b7b"),
"value" : "6264319819636d7db1804b7e",
"name" : "Body Type"
},
{
"_id" : ObjectId("62643acf19636d7db1804cb6"),
"parent" : ObjectId("626431ef19636d7db1804b82"),
"value" : "626431ef19636d7db1804b83",
"name" : "Bore Type"
},
{
"_id" : ObjectId("62643acf19636d7db1804cb7"),
"parent" : ObjectId("6264328519636d7db1804b85"),
"value" : "6264328519636d7db1804b86",
"name" : "Material Type"
},
{
"_id" : ObjectId("62643acf19636d7db1804cb8"),
"parent" : ObjectId("626435de19636d7db1804c10"),
"value" : "626439b619636d7db1804ca7",
"name" : "Trim Material"
},
{
"_id" : ObjectId("62643acf19636d7db1804cb9"),
"parent" : ObjectId("6264367919636d7db1804c17"),
"value" : "6264367919636d7db1804c18",
"name" : "End Conection"
},
{
"_id" : ObjectId("62643acf19636d7db1804cba"),
"parent" : ObjectId("626436a719636d7db1804c1f"),
"value" : "6264378119636d7db1804c28",
"name" : "Size"
},
{
"_id" : ObjectId("62643acf19636d7db1804cbb"),
"parent" : ObjectId("6264389219636d7db1804c6d"),
"value" : "6264389219636d7db1804c6f",
"name" : "Class / Pressure"
}
],
"subFilter" : [
{
"_id" : ObjectId("62643acf19636d7db1804cbc"),
"parent" : "6264328519636d7db1804b85",
"value" : "626433b919636d7db1804b93",
"title" : "Body Material"
}
],
"createdAt" : ISODate("2022-04-23T17:43:43.421+0000"),
"updatedAt" : ISODate("2022-04-23T17:53:29.016+0000"),
"__v" : NumberInt(0)
}
Consider this shrunk down set of inputs that capture the essence of the question. The comments "give away" what we are going to try to find and why. We only show one value for category because matching on that is trivial and not the interesting part of the query.
[
{
"category" : ObjectId("62445c4d922d127512867246"),
"filters" : [
// Matching Valve/value; include this doc
{"name" : "Valve", "value" : "626430bb19636d7db1804b78"},
// ALSO match Body/value; include this doc (but needs only 1 match)
{"name" : "Body", "value" : "6264319819636d7db1804b7e"}
]
}
,{
"category" : ObjectId("62445c4d922d127512867246"),
"filters" : [
// Not target value for Valve name (..79 instead of ...78):
{"name" : "Valve", "value" : "626430bb19636d7db1804b79"},
// ...but correct value for Body, so include this doc
{"name" : "Body", "value" : "6264319819636d7db1804b7e"}
]
}
,{
"category" : ObjectId("62445c4d922d127512867246"),
// No matching Valve or Body so this whole doc is ignored.
"filters" : [
{"name" : "Valve", "value" : "626430bb19636d7db1804b79"},
{"name" : "Body", "value" : "6264319819636d7db1804b7f"}
]
}
,{
"category" : ObjectId("62445c4d922d127512867246"),
// Not even name matches so ignore this too:
"filters" : [
{"name" : "Pipe", "value" : "6264319819636d7db1804eee"}
]
}
]
Assume also we set up inputs coming from the API like this, in their native form i.e. strings NOT ObjectId:
var targ_cat = '62445c4d922d127512867246';
var any_one_of = [
{ name: 'Valve', value: '626430bb19636d7db1804b78' },
{ name: 'Body', value: '6264319819636d7db1804b7e'}
];
We will use $filter as our main function but to do so, we must convert the incoming material into a form required by $filter.
// Convert inbound array of any_one_of into a something designed to work
// in the $filter function by comparing each name/value entry in the
// filters field to the item presented in $$this, meaning take:
// { name: 'Valve', value: '626430bb19636d7db1804b78' },
// and turn it into:
// {$and: [ {$eq:['Valve','$$this.name']}, {$eq:['62643...','$$this.value']} ] }
// Since any one of the entries is considered a hit, we package it all
// into an $or wrapper, not $and.
var or_list = [];
any_one_of.forEach(function(f) {
or_list.push( {$and: [
{$eq:[f['name'], '$$this.name']},
{$eq:[f['value'], '$$this.value']}
]});
});
var or_expr = {$or: or_list};
Now we are ready to query mongoDB:
db.foo.aggregate([
// Get this out of the way quickly; note we must make a new ObjectId!
{$match: {'category': new ObjectId(targ_cat)}}
// The interesting part of the query:
,{$addFields: {filters: {$filter: {input: '$filters', cond: or_expr}}}}
// Only keep those items where $filter found at least one of the
// targets:
,{$match: {$expr: {$gt:[{$size: '$filters'},0]} }}
]);

Display data on screen based on the values selected from the form

I have to display the data on the screen based on the input received via radio buttons by applying certain conditions. I also need help with fetching the id of an object when the name attribute is selected from the radio button. Here is are the arrays of objects
arrayOfObjects = [
{hiringTypeName : "lateral", hiringTypeId :1,compCode : "IB", compId : 400},
{hiringTypeName : "new", hiringTypeId :2,compCode : "IB", compId : 401},
{hiringTypeName : "lateral", hiringTypeId :3,compCode : "BITS", compId : 402},
{hiringTypeName : "new", hiringTypeId :4,compCode : "BITS", compId : 403},
]
moduleArray =[
{processName : "offer", processId : 1,data:[{
name : "demo1",
id : 1
}]},
{processName : "hire", processId : 2,data:[{
name : "demo1",
id : 1
}]}
]
From a different API call i'll get the data from the server which will look like (*for refrence only)
dummyData = [
{processName : "offer",
processId : 1,
hiringTypeId :1,
data:[{
showName : "demo1", showId : 1
}]},
{processName : "hire",
processId : 2,
hiringTypeId :1,
data:[{
showName : "demo2", showId : 1
}]},
{processName : "offer",
processId : 2,
hiringTypeId :3,
data:[{
showName : "demo3", showId : 1
}]},
]
It will have processName, processId and companyHiringtypeId and each combination of these three will have a array of objects called 'data' associated with it. I want to display the showName in data on he screen based on the selection.
Here is a stackblitz that I have created with all the basic arrays and form made and described what I need in the comments in the .ts file. I have tried to keep the code as clean as I could and to the point. Please ask me for more clarification on the same. Thank You
I edited my answer based on your last comment. In the app.component.ts:
showDummyData() {
this.selectedDummyData = this.dummyData.filter(a => a.processName === this.selected
&& a.hiringTypeId === +this.selected1);
}
And in app.component.html:
<div *ngFor="let item of selectedDummyData">
{{item.data[0].showName}}
</div>
And here the Stackblitz based on your code: https://stackblitz.com/edit/angular-fpqbiv
Select the two radio buttons and click "Show Selected Dummy Data".

How to combine JSON objects with equal values within Backbone.js

I am trying to display multiple "unread" alerts, but need to attach the organizations label to it if the organizations id is equal to the unread domainId.
How can I acheive this while displaying the results in a handlebars #each function?
JSON
"alerts" : {
"organizations" : [ {
"id" : 165,
"label" : "Label #1"
}, {
"id" : 170,
"label" : "Label #2"
}],
"unread" : [ {
"id" : 20022,
"domainId" : 170,
"created" : "2015-10-13T16:48:08Z",
}, {
"id" : 20022,
"domainId" : 165,
"created" : "2015-10-13T16:48:08Z",
}]
};
Backbone.js:
context: function() {
var d = this.options.data
return {
welcomeAlerts: d.alerts,
welcomeOrg: d.alerts.organizations.label
}
},
Handlebars//HTMl
{{#each welcomeAlerts.unread}}
<li class="alert-item stripe-list-item">
<h4 class="org">{{welcomeOrg}}</h4>
<h4 class="timestamp">{{created}}</h4>
</li>
{{/each}}
Simply transform the data beforehand
var data = {
"alerts" : {
"organizations" : [ {
"id" : 165,
"label" : "Label #1"
}, {
"id" : 170,
"label" : "Label #2"
}],
"unread" : [ {
"id" : 20022,
"domainId" : 170,
"created" : "2015-10-13T16:48:08Z",
}, {
"id" : 20022,
"domainId" : 165,
"created" : "2015-10-13T16:48:08Z",
}]
}
};
var organizationDict = _.groupBy(data.alerts.organizations, 'id');
var unreadWithOrganizations = _(data.alerts.unread)
.map((message) => {
return {
...message,
organization: organizationDict[message.domainId]
}
})
.value();
and display your data
{{#each unreadWithOrganizations}}
<li class="alert-item stripe-list-item">
<h4 class="org">{{organization.label}}</h4>
<h4 class="timestamp">{{created}}</h4>
</li>
{{/each}}
Demo: http://jsbin.com/sadoluhepu/edit?js,console
I've made an example using lodash library and es6. You might want to stick with ES6 and underscore, which implementation might differ.

AngularJS nested ngRepeat on same element

Is there a way to perform nested loops in an AngularJS view without creating hidden dummy elements?
Something like this:
<ul>
<li ng-repeat="gem in activeHero.gems"
ng-repeat="(key, value) in gem.attributes"
ng-repeat="attr in value">
{{attr.text}}
</li>
</ul>
or this
<ul>
<li ng-repeat-start="gem in activeHero.gems"
ng-repeat-start="(key, value) in gem.attributes"
ng-repeat="attr in value">
{{attr.text}}
</li ng-repeat-end
ng-repeat-end>
</ul>
Neither of these is possible AFAIK.
I basically want my HTML to have a different structure than the JSON it's based on.
How could I achive this? Is there a way to create loops inside a view without an HTML element?
The examples above would loop over a JSON structure like this:
JSON (stripped out a lot for clarity)
"activeHero" = {
"gems" : [ {
"attributes" : {
"primary" : [ {
"text" : "+220 Intelligence"
} ],
"secondary" : [ ],
"passive" : [ ]
}
}, {
"attributes" : {
"primary" : [ {
"text" : "+220 Intelligence"
} ],
"secondary" : [ ],
"passive" : [ ]
}
}, {
"attributes" : {
"primary" : [ {
"text" : "+160 Intelligence"
} ],
"secondary" : [ ],
"passive" : [ ]
}
} ]
}
(This is an actual JSON response from the Blizzard API for the video game "Diablo 3")
Try format your json before render;
$scope.formattedData = [];
angular.forEach(activeHero.gems, function(value, key){
var item = {
//set filed you want
}
angular.forEach(value.atrtibutes, function(value2, key2){
item['propyouwant'] = value2[propyouwant]
angular.forEach(value2.primary, function(value3, key3){
item['propyouwant'] = value3[propyouwant]
$scope.formattedData.push(angular.extend({}, item));
})
})
})
//now you can render your data without somersould
EDIT
For increasing performance and avoid to use angular extend;
$scope.formattedData = [];
angular.forEach(activeHero.gems, function(value, key){
angular.forEach(value.atrtibutes, function(value2, key2){
angular.forEach(value2.primary, function(value3, key3){
//start build your item here
var item = {
prop1: value['prop'],
prop2: value2['prop']
}
//not required extend item;
$scope.formattedData.push(item);
})
})
})

jQuery + table creation from json

I have a JSON file
{
"Scenario" : "ModelNameHere",
"id" : "1",
"description" : "Description of table model goes here",
"headers" : {
"Column 1 header" : {
"order" : 1,
"items" : {
"Row 1 Col 1 value" : {
"id" : 1,
"comment" : "Comment on Row 1 Col 1",
"order" : 1
},
"Row 2 Col 2 value" : {
"id" : 2,
"comment" : "Comment on Row 2 Col 2",
"order" : 2
}
}
},
"Column 2 header" : {
"order" : 2,
"items" : {
"Row 1 Col 2 value" : {
"id" : 3,
"comment" : "Comment on Row 1 Col 2",
"order" : 1
},
"Row 2 Col 2 value" : {
"id" : 4,
"comment" : "Comment on Row 2 Col 2",
"order" : 2
}
}
}
}
}
I want to use jQuery to put the JSON data into an HTML table.
Headers should go inside TH td items, items inside headers should be elements in the TD of each related row.
Is there a function in either JS or jQuery to populate a table with JSON data?
How would I loop through and match JSON elements to table elements?
Thanks.
No, there is no such function as it is a really situational specific function.
It's quite easy to write though.
You can acces the JSON as a normal JS object.
This means you can just loop trough it and put the information in the right spots.
This question explores various templating engines, which could help you with what you are trying to achieve. You would still need to define the template for the table, but populating it will be very easy.
Look at this plugin. There are many jQuery plugins so choose one that suits you.
http://www.datatables.net
Here is example from json, except that it is loaded from txt file but that is not problem.
http://www.datatables.net/examples/data_sources/ajax.html
And here is how I suggest you restructure your json. In my honest opinion you should think here in terms of tables and not objects.
{
"model" : "Model name here",
"id" : 1,
"description" : "Description of table model goes here",
"headers" : {
"header" : {
"id" : 1,
"order" : 1,
"name" : "Col 1 header name"
},
"header" : {
"id" : 2,
"order" : 3,
"name" : "Col 2 header name"
}
},
"row1" : {
"item" : {
"id" : 1,
"name" : "Some td data comes here"
},
"item2" : {
"id" : 4,
"name" : "Some td data comes here"
}
},
"row2" : {
"item" : {
"id" : 2,
"name" : "Some td data comes here"
},
"item2" : {
"id" : 3,
"name" : "Some td data comes here"
}
}
}
if u r doing in PHP then use json_decode('jsonstring',true);
that will comes as array and easily manipulate the array to create html

Categories