Nested JSON in one ng-repeat - json

I'm somewhat new to angular, and i'm having problems with ng-repeats. I have one ng-repeat that have to show nested objects in each repeat. You know what I mean?
This is the HTML:
<li ng-repeat="rm in rooms">
<a href="">
<span id="room">{{rm.room}}</span>
<span id="rack_num">Rack {{rm.rack}}</span>
<span id="slot_type">{{rm.type}}</span>
<span id="slot_id">Slot {{rm.id}}</span>
</a>
</li>
I have a list of "rooms" and "racks" and "slots":
[
{
"room": 1,
"rackroom": [
{
"rack": 8,
"rackslots": [
{
"slot": 1,
"id": "EZ345T1R",
"type": "single"
}
]
},
{
"rack": 12,
"rackslots": [
{
"slot": 3,
"id": "56XZU28",
"type": "double"
}
]
}
]
},
{
"room": 2,
"rackroom": [
{
"rack": 12,
"rackslots": [
{
"slot": 1,
"id": "TZE57DG",
"type": "single"
}
]
},
{
"rack": 32,
"rackslots": [
{
"slot": 7,
"id": "778GHRT",
"type": "double"
}
]
}
]
}
]
My controller looks like this:
$http.get('data/data.json').success(function(data) {
$scope.rooms = [];
$scope.slots = [];
$scope.racks = [];
angular.forEach(data, function(key, val){
$scope.rooms.push(key);
angular.forEach(key.rackroom, function(key, val){
$scope.racks.push(key);
angular.forEach(key.rackslots, function(key, val){
$scope.slots.push(key);
});
});
});
});
The output should look something like this:
• Room: 1
• Rack: 12
• Type: single
• Slot: 3
• Room: 1
• Rack: 24
• Type: single
• Slot: 8
It seems like I'm wrong because just the rooms appear but not the nested objects. If I make 3 separate repeats (slot in slots, rack in racks, room in rooms) they all appeear, but I need it all in one repeat ...
Thank you for Help!

You basically need to flatten your nested data:
$http.get('data/data.json').success(function(data) {
$scope.rooms = [];
for (var i = 0; i < data.length; i++) {
var room = data[i];
for (var j = 0; j < room.rackroom.length; j++) {
var rack = room.rackroom[j];
for (var k = 0; k < rack.rackslots.length; k++) {
var slot = rack.rackslots[k];
$scope.rooms.push({
room: room.room,
rack: rack.rack,
slot: slot.slot,
type: slot.type
});
}
}
}
});
<li ng-repeat="rm in rooms">
<a href="">
<span id="room">{{rm.room}}</span>
<span id="rack_num">Rack {{rm.rack}}</span>
<span id="slot_type">{{rm.type}}</span>
<span id="slot_id">Slot {{rm.slot}}</span>
</a>
</li>

I think the following is very close to what you want:
var app = angular.module('demo', []);
app.controller('MainCtrl', function($scope) {
var data = [{
"room": 1,
"rackroom": [{
"rack": 8,
"rackslots": [{
"slot": 1,
"id": "EZ345T1R",
"type": "single"
}]
}, {
"rack": 12,
"rackslots": [{
"slot": 3,
"id": "56XZU28",
"type": "double"
}]
}]
}, {
"room": 2,
"rackroom": [{
"rack": 12,
"rackslots": [{
"slot": 1,
"id": "TZE57DG",
"type": "single"
}]
}, {
"rack": 32,
"rackslots": [{
"slot": 7,
"id": "778GHRT",
"type": "double"
}]
}]
}];
$scope.rooms = [];
angular.forEach(data, function(room) {
angular.forEach(room.rackroom, function(rack) {
angular.forEach(rack.rackslots, function(slot) {
$scope.rooms.push({
room: room.room,
rack: rack.rack,
type: slot.type,
slot: slot.slot
});
});
});
});
});
.room,
.rack_num,
.slot_type,
.slot_id {
display: list-item;
}
.room_item {
margin: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app="demo" ng-controller="MainCtrl">
<ul>
<li class="room_item" ng-repeat="rm in rooms">
<a href="">
<span class="room">Room: {{rm.room}}</span>
<span class="rack_num">Rack: {{rm.rack}}</span>
<span class="slot_type">Type: {{rm.type}}</span>
<span class="slot_id">Slot {{rm.slot}}</span>
</a>
</li>
</ul>
</div>
The markup may not quite be right, but you can tweak it from here.
Also, if you are going to repeat something, you shouldn't use id for those elements. ids are supposed to be unique across the whole page. Use classes instead, like I did.

Related

How to make dynamic Sidebar from Json api?

I am trying to create a React Dynamic Sidebar from the Json API.
I need a coding assist for double iteration in React by using below three conditions:
if json element id === 0 ===> outer 1st level Mennuitem
if json element[i] id ===[j] parent_id ===> 2nd level submenu item
if parent_id[i]===[j] id && [j]parent_id===0 ===>3rd level submenuitem
But I can achieve outer MenuItem. But I fail to create SubMenuItem.
Please help me to fix this issue. Please see the attached image. Thanks
class App extends Component {
constructor(props) {
super(props);
this.state = {
mz:[
{
"id": 1,
"name": "Menu1",
"parent_id": 0
},
{
"id": 9,
"name": "SubMenu1-Menu1",
"parent_id": 1
},
{
"id": 26,
"name": "8989",
"parent_id": 9
},
{
"id": 10,
"name": "SubMenu2-Menu1",
"parent_id": 1
},
{
"id": 2,
"name": "Menu2",
"parent_id": 0
},
{
"id": 11,
"name": "SubMenu1-Menu2",
"url": "",
"order": 210,
"type": 3,
"is_active": true,
"parent_id": 2
},
{
"id": 12,
"name": "SubMenu2-Menu2",
"url": "",
"order": 220,
"type": 3,
"is_active": true,
"parent_id": 2
}],};
}
render() {
return (
<div>
{this.state.api.filter((el) => (el.parent_id === 0 ? el.name : null)).map((el) => (
<ReactBootStrap.Navbar >
{el.name}
<ReactBootStrap.NavDropdown>
{(el.parent_id === el.id ? el.name : null).map((el) =>el.name)}//I CANNOT ITERATE CORRECTLY THIS PART
</ReactBootStrap.NavDropdown>
</ReactBootStrap.Navbar>
))}
</div>
);
}
}
export default App;
see this map:
this.state.mz.map(item => {
if(item.parent_id === 0){
output[item.id] = item
} else {
if(!output[item.parent_id]['submenu']){
output[item.parent_id]['submenu'] = {}
}
output[item.parent_id]['submenu'][item.id] = item
}
})

Normalizr usage for deep nested obj

I am trying to use Normalizr for normalize and denormalize object that I am using within my angular ngrx app.
I found almost the solution for it here:https://www.snip2code.com/Snippet/1028240/Deep-nested-tree-normalize-with-normaliz
import {normalize, Schema, arrayOf} from 'normalizr';
var data = [
{
"id": 1,
"name": "О компании",
"children": [
{
"id": 5,
"name": "Руководство",
"children": [
{
"id": 6,
"name": "Генеральный директор",
"children": [
{
"id": 20,
"name": "Зам гендира"
},
{
"id": 8,
"name": "Секретарша"
}
]
},
{
"id": 7,
"name": "Главный бухгалтер",
"children": [
{
"id": 21,
"name": "Зам главбуха"
}
]
}
]
}
]
},
{
"id": 2,
"name": "Вакансии",
"children": [
{
"id": 9,
"name": "Фронтенд-разработчик (JS)"
},
{
"id": 10,
"name": "Бэкэнд-разработчик (Java)"
},
{
"id": 11,
"name": "Оператор ЭВМ"
}
]
}
];
The thing is that many functions from solution below changed and it is little bit hard for me to use same solution with newer release of normalizr. Maybe some of you know how to rewrite below solution into new normalizr?
var node = new Schema('nodes');
node.define({
children: arrayOf(node)
});
var treeSchema = arrayOf(node);
var normalizedData = normalize(data, treeSchema);
console.log(normalizedData);
You're looking at an example using an outdated version of Normalizr. Try reading the docs for new APIs
I did it :)
const node = new schema.Entity('nodes');
node.define({
children: [node]
})
const treeSchema = [node];
const normalizedData = normalize(this.form,treeSchema);

Unable to get the length of JSON object

I am getting 'TypeError: Cannot convert undefined or null to object' while trying to access the length of json object in nodejs.
Following is how my data looks like:
{
"college": [
{
"colleges": [],
"department": [
1,
2,
3
],
"general_course": [],
"id": 1,
"name": "College of the Arts",
"short_name": "",
"url": "/content.php?catoid=16&navoid=1919"
},
{
"colleges": [],
"department": [
4,
5,
6
],
"general_course": [],
"id": 2,
"name": "College of Communications",
"short_name": "",
"url": "/content.php?catoid=16&navoid=1920"
},
{
"colleges": [],
"department": [
7,
12
],
"general_course": [],
"id": 3,
"name": "College of Education",
"short_name": "",
"url": "/content.php?catoid=16&navoid=1921"
},
{
"colleges": [],
"department": [
13,
17,
19
],
"general_course": [],
"id": 4,
"name": "College of Engineering and Computer Science",
"short_name": "",
"url": "/content.php?catoid=16&navoid=1922"
},
{
"colleges": [],
"department": [
20,
26,
27
],
"general_course": [],
"id": 5,
"name": "College of Health and Human Development",
"short_name": "",
"url": "/content.php?catoid=16&navoid=1923"
},
{
"colleges": [],
"department": [
28,
29,
32,
48
],
"general_course": [],
"id": 6,
"name": "College of Humanities and Social Sciences",
"short_name": "",
"url": "/content.php?catoid=16&navoid=1924"
},
{
"colleges": [],
"department": [
52,
57
],
"general_course": [],
"id": 7,
"name": "College of Natural Sciences and Mathematics",
"short_name": "",
"url": "/content.php?catoid=16&navoid=1925"
},
{
"colleges": [],
"department": [
58,
59,
63
],
"general_course": [],
"id": 8,
"name": "Mihaylo College of Business and Economics",
"short_name": "",
"url": "/content.php?catoid=16&navoid=1926"
}
]
}
Step 1 - Parsing it into nodejs:
let colleges = JSON.parse(data)
Step 2 - Saving it into the dialogflow app data:
app.data.collegeData = data;
Step 3 - Accessing the length:
let collegeLength = Object.keys(app.data.collegeData.college).length;
Getting following error in firebase console:
TypeError: Cannot convert undefined or null to object
Update:
Here is the code:
if ( app.data.collegeData === undefined ){
app.data.collegeData = [];
}
**Step 1 =>**
showColleges(college);
**Step 2 =>**
function showColleges(collegeName){
if (app.data.collegeData.length === 0){
getCollegeData().then(buildSingleCollegeResponse(collegeName))
.catch(function (err){
console.log('No college data')
console.log(err)
});
}
else{
buildSingleCollegeResponse(collegeName);
}
}
**Step 3 =>**
function getCollegeData(){
console.log('Inside get College Data')
return requestAPI(URL)
.then(function (data) {
let colleges = JSON.parse(data)
if (colleges.hasOwnProperty('college')){
saveData(colleges)
}
return null;
})
.catch(function (err) {
console.log('No college data')
console.log(err)
});
}
**Step 4 =>**
function saveData(data){
app.data.collegeData = data;
console.log(app.data.collegeData)
}
**Step 5 =>**
function buildSingleCollegeResponse(collegeName){
let responseToUser, text;
//console.log('Data is -> '+ Object.keys(app.data.collegeData.college).length);
//console.log('Length is -> '+ app.data.collegeData.college.length);
console.log('Count is -> '+app.data.collegeCount);
let collegeLength = Object.keys(app.data.collegeData.college).length;
if ( collegeLength === 0){
responseToUser = 'No colleges available at this time';
text = 'No colleges available at this time';
}
else if ( app.data.collegeCount < collegeLength ){
for ( var i = 1; i <= collegeLength; i++)
{
console.log('All Colleges:: '+app.data.collegeData.college[i])
let coll = app.data.collegeData.college[i]
let name = coll.name
console.log('checkCollegeExist => College Name:: '+ name)
console.log('checkCollegeExist => Parameter => College Name:: '+collegeName)
if(String(name).valueOf() === String(collegeName).valueOf()){
responseToUser = 'Yes! CSUF has '+collegeName;
text = 'Yes! CSUF has '+collegeName;
}else{
responseToUser = 'CSUF does not teach ' +collegeName+' currently';
text = 'CSUF does not teach ' +collegeName+' currently';
}
}
}
else{
responseToUser = 'No more colleges';
}
if (requestSource === googleAssistantRequest) {
sendGoogleResponse(responseToUser);
} else {
sendResponse(text);
}
}
This is the culprit:
getCollegeData().then(buildSingleCollegeResponse(collegeName))
That calls buildSingleCollegeResponse(collegeName) and then passes its return value into then, just like foo(bar()) calls bar and passes its return value into foo.
You wanted to pass a functon to then:
getCollegeData().then(() => buildSingleCollegeResponse(collegeName))
// An arrow function ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Note that now that it's clear from the updated question that app.data.collegeData.college is an array, there's no need for Object.keys. Change:
let collegeLength = Object.keys(app.data.collegeData.college).length;
to simply
let collegeLength = app.data.collegeData.college.length;
Arrays have a length property (whereas non-array objects don't, by default).
You haven't mentioned what value app.data holds before issuing app.data.collegeData = data;
If app.data is undefined you should try app.data = {collegeData: data}
Or else negating what app stores. Following works
app = {};
app.data = {};
app.data.collegeData = data;
app.data.collegeData.college.length
You don't need to do the following
let collegeLength = Object.keys(app.data.collegeData.college).length;
Update: Refer to https://jsfiddle.net/dmxuum79/3/

How to get response (array of json) and put it in my html component in Angular 4

I am trying to get the array data in a JSON response. The following is my JSON response and I need to get all data to my html tags in component.
{
data : {
"topLikedMedia" : [
{
"id": "1546567845943506613_3718981156",
"type": "image",
"user": {
"id": "3718981156",
"username": "agoramonitor",
"full_name": "AgoraMonitor",
"profile_picture": "https://scontent.cdninstagram.com/t51.2885-19/s150x150/18809269_476795959342067_7353566623065702400_n.jpg"
},
"tags": [
"instagramers",
"content",
"socialmedia",
"marketing",
"branding",
"instagram"
],
"location": null,
"comments": {
"count": 2
},
"formatted_comments_count": "2",
"created_time": "1498585275",
"formatted_time": "Tue, Jun 27, 2017 7:41 PM",
"diff_humans_time": "4 months ago",
"link": "https://www.instagram.com/p/BV2g0MGgPa1/",
"likes": {
"count": 154
},
"formatted_likes_count": "154",
"images": {
"thumbnail": {
"width": 150,
"height": 150,
"url": "https://scontent.cdninstagram.com/t51.2885-15/s150x150/e35/c244.0.591.591/19533988_862713503881059_8677706625265434624_n.jpg"
},
"low_resolution": {
"width": 320,
"height": 175,
"url": "https://scontent.cdninstagram.com/t51.2885-15/s320x320/e35/19533988_862713503881059_8677706625265434624_n.jpg"
},
"standard_resolution": {
"width": 640,
"height": 350,
"url": "https://scontent.cdninstagram.com/t51.2885-15/s640x640/sh0.08/e35/19533988_862713503881059_8677706625265434624_n.jpg"
}
},
"caption": "Whether you want to drive leads to your homepage or encourage customer engagement ",
"userHasLiked": false,
"filter": "Normal"
}
],
}
I have the temp of this output and I need to receive this response and distribute it on its own tags and i dont know how
First solution, the Angular way :
getTopLiked() {
this._dashboardService.getTopPosts()
.subscribe(res => {
// Get your data in your component's variable
this.data = res.json();
});
}
In your HTML
<div *ngIf="data">
<div *ngFor="let liked of data.topLikedMedia">
<p>ID : {{liked.id}}</p>
<!-- And you do every other field like that -->
</div>
</div>
Second solution, the old Javascript way
getTopLiked() {
this._dashboardService.getTopPosts()
.subscribe(res => {
this.createMarkup(res.json());
});
}
createMarkup(data: Object) {
this.markup = '';
for (let liked of data.topLikedMedia) {
this.markup += `<p>ID : ${liked.id}</p>`;
// add the other fields like that
}
}
In your HTML
<div *ngIf="markup">
<div [innerHTML]="markup"></div>
</div>

Map two Collections (Inner Join) using AngularJS HTML

I'm having two Collection user and Type. I wish to dispay Email ID which is marked as IsPreffered = TRUE and I need to map the email.Type to Type.ID
{ "user" : [
{
"Name" : "B. Balamanigandan",
"Email": [
{
"Id": "bala#gmail.com",
"IsPreffered": true,
"Type": 1,
},
{
"Id": "mani#gmail.com",
"IsPreffered": false,
"Type": 2,
}
]}
]};
{
"Type": [
{
"ID": 1,
"Name": "Private"
},
{
"ID": 2,
"Name": "Home"
},
{
"ID": 3,
"Name": "Business"
},
]}
HTML Source Code:
<span ng-repeat="email in collection.user[0].Email | filter: {IsPreffered : true} " ng-if="$last"> {{email.Id}}</span>
Here I need to Specify the Type "Private" for the above HTML. How to Map the user[0].Email.Type to Type.ID and fetch the appropriate Type.Name
Kindly filter the condition using HTML Level not in JavaScript Level. Kindly assist me.
I would suggest doing it in code rather than the markup, but if you need this is one way you can map to Type:
<span
ng-repeat="email in collection.user[0].Email| filter: {IsPreffered : true} "
ng-if="$last">
Email : {{email.Id}} ,
<span ng-repeat="typename in typeCollection.Type|filter:{ID : email.Type}">
Type: {{typename.Name}}
</span>
</span>
where typeCollection is :
$scope.typeCollection = {
"Type": [{
"ID": 1,
"Name": "Private"
}, {
"ID": 2,
"Name": "Home"
}, {
"ID": 3,
"Name": "Business"
}, ]
};
Please note that you needed one more ng-repeat in markup because filter works on an array.
EDIT:
You can also do this using ng-init:
<span
ng-repeat="email in collection.user[0].Email| filter: {IsPreffered : true} "
ng-if="$last">
Email : {{email.Id}} ,
<span ng-init="types = (typeCollection.Type|filter:{ID : email.Type})">
Type: {{types[0].Name}}
</span>
</span>
for(var i = 0; i < Type.length ; i++)
{
if(user[0].Email.Type to Type[i].ID)
{
user[0].Email.TypeName = Type[i].ID;
}
};
Html
<span ng-repeat="email in collection.user[0].Email | filter: {IsPreffered : true} " ng-if="$last">{{email.TypeName}} : {{email.Id}}</span>