Display nested list in angular 2 - javascript

I want to display nested list. The structure of the list:
[
{
name: "Level 1A",
children: [
{
name: "Level 2A",
children: [
]
},
{
name: "Level 2B",
children: [
{
name: "Level 3A",
children: [...]
}
]
}
]
},
{
name: "Level 1B",
children: [
{
name: "Level 2A"
children: [...]
}
]
}
]
As you can see we have items with 2 properties: name and children. It could be nestem many many levels down.
The HTML output should be something like this:
<list>
<list-grup name="Level 1A">
<list-item name="Level 2A"></list-item>
<list-item name="Level 2B"></list-item>
</list-grup>
<list-grup name="Level 1B">
<list-item name="Level 2A"></list-item>
</list-grup>
</list>
The only way i found is to display it like this:
<list>
<ng-container *ngFor="let item of list">
<list-group *ngIf="item.children" [item]="item.name">
<ng-container *ngFor="let item1 of item.children">
<list-group [item]="item1.name">
<list-group *ngIf="item1.children" [item]="item1.name">
<ng-container *ngFor="let item2 of item1.children">
...
</ng-container>
</list-group>
</list-group>
</ng-container>
</list-group>
</ng-container>
</list>
But this way is incorrect because I dont want it to be hardcoded because this data will be dynamic.
Can you help me find better solution to display this data? It could be done in template or component.

One possible way is to create a component which represents a single Node (name, children)
first the interface:
export interface Node {
name: string;
children: Node[];
}
component with one #Input() binding
export class NodeComponent implements OnInit {
#Input() node: Node;
html
<li>
<p>{{node.name}}</p>
<ul *ngFor="let item of node.children">
<app-node [node]="item"></app-node>
</ul>
</li>
begin the whole process from:
<ul>
<ng-container *ngFor="let item of list">
<app-node [node]="item"></app-node>
</ng-container>
</ul>
Working Stackblitz
Version with Expand/Collapse support

Related

How to display nested json array with v-for index loop

I have JSON Array with following structure
items: [
{
ID: 11,
UserID: "test.com",
UserRole: "user",
timeStamp: "2021-03-23T15:54:02.125578",
dialogs: [
{
"Bot": "Why is data missing?",
"test.com": "not available",
"Bot": "please enter ID",
"test.com": "1234"
}
]
}
]
I have to display elements inside dialogs as list. i am using v-for but dialogs is displaying as array with commas. how can i show this with index? Following is v-for loop i am using
<ul v-for="item in items" :key="item">
<li v-for="(dialog, index) in dialogs" :key="index">{{key}}: {{dialogs}}</li>
</ul>
<ul v-for="item in items" :key="item">
<li v-for="(dialog, index) in item.dialogs" :key="index">{{index}}: {{dialog}}</li>
</ul>
There are 2 changes required.
In your dialogs you have duplicate keys, so they need to separated out into two different objects.
In your HTML part you need to loop as items.dialogs
Here is the full code.
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!',
items: [
{
ID: 11,
UserID: "test.com",
UserRole: "user",
timeStamp: "2021-03-23T15:54:02.125578",
dialogs: [
{
"Bot": "Why is data missing?",
"test.com": "not available",
},
{"Bot": "please enter ID",
"test.com": "1234"
}
]
}
]
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul v-for="(item, index) in items" :key="item">
<li v-for = "(data, index) in item.dialogs">
{{data}} {{index}}</li>
</ul>
</div>

Render Object Array Properties In a Single Line

I have an object like below. I need to render all the subcategoryList names to an Angular HTML template as single line. I use this kind of solution print array in a single line: someObject.languages.join(' , '). What type of method can I use for this? I can't use *ngFor because it will render separate line for each object item.
{
firstName: " Hello",
lastName: "World",
category: [{
catId: "1",
catName: "SomeCat"
subcategoriesList: [{
subcatId: "5",
subcatName: "SubSomeCat"
},
{
subcatId: "6",
subcatName: "SubSomeCat1"
}
]
}, {
catId: "2",
catName: "SomeCat2"
subcategoriesList: [{
subcatId: "9",
subcatName: "SubSomeCat"
},
{
subcatId: "10",
subcatName: "SubSomeCat1"
}
]
}]
}
Either you can change the structure to a more flattened way. Or you can use span or inline div's.
<span *ngFor="let category of data.category">
<span *ngFor="let subcategory of category.subcategoriesList">
{{subcategory.subCatName}}
</span>
</span>
From what I understood, you want all sub-catgeory names as single string in HTML. You can use angular pipe to transform the data before displaying it on UI.
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'categoryNames'
})
export class CategoryNamesPipe implements PipeTransform {
public transform(obj: unknown): any {
return category
.map(list =>
list.subcategoriesList.map(subCatgeory => subCatgeory.name).join(', ')
)
.join(', ');
}
}
HTML:
<span> {{fullCatgeoryObj | categoryNames}}</span>
As Arcteezy mentioned it can be done with a hack, By default DIV render as display:block and SPAN as display:inline.
----------------------------USING SPAN--------------------------
<br>
<span *ngFor="let category of myData.category">
<span *ngFor="let subcategory of category.subcategoriesList">
{{subcategory.subcatName}}
</span>
</span>
<br>
----------------------------USING DIV------------------
<BR>
<div *ngFor="let category of myData.category" style="float:left">
<div *ngFor="let subcategory of category.subcategoriesList" style="float:left">
{{subcategory.subcatName}}
</div>
</div>
STACKBLITZ DEMO

I am looking for a way to do a multi-column Dropdown Listbox using Kendo in an Angular 7 project

I'm attempting to recreate the multi-column Kendo DropDownList found at the following link.
kendoDropDownList
I've been able to recreate most of it using the following code, but it will not display the data properly.
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-tablebox',
// templateUrl: './tablebox.component.html',
styleUrls: ['./tablebox.component.scss'],
template: `
<div>
<kendo-dropdownlist style="width:400px;"
[defaultItem]="defaultItem"
[data]= "data"
[textField]= "'band'"
[valueField]= "'id'"
>
<ng-template kendoDropDownListHeaderTemplate>
<table>
<tr class="combo-tr">
<td class="combo-hd-td">Band</td>
<td class="combo-hd-td">Song</td>
<td class="combo-hd-td">Album</td>
</tr>
</table>
</ng-template>
<ng-template kendoDropDownListValueTemplate let-dataItem>
<span>
<table>
<tr class="combo-tr">
<td class="combo-td">{{dataItem.band}}</td>
<td class="combo-td">{{dataItem.song}}</td>
<td class="combo-td">{{dataItem.album}}</td>
</tr>
</table>
</span>
</ng-template>
</kendo-dropdownlist>
</div> `
})
export class TableboxComponent {
public defaultItem: { text: string, value: number } = { text: "Select item...", value: null };
public data = [
{ id: 1, band: "Iron Maiden", song: "Wasted Years", album: "Ed Hunter" },
{ id: 2, band: "Metallica", song: "Enter Eandman", album: "Metallica" },
{ id: 3, band: "Mr. Big", song: "Seven Impossible Days", album: "Japandemonium" },
{ id: 4, band: "Unknown Band", song: "Some Song", album: "The Album" }
];
constructor() { }
}
The component displays as follows:
Screenshot
Thanks in advance.
Mike
You should use kendoDropDownListItemTemplate instead of kendoDropDownListValueTemplate.
kendoDropDownListValueTemplate is the template used for the item that appears in the dropdown after you've selected an item.
kendoDropDownListItemTemplate is the template used for the items in the list.

Displaying Objects in an Array VueJS

So I am using a JSON object that looks something like this:
data: [
{
title: "Post Title One",
categories: {
data: [
{
id: 1,
name: "Category Name 1"
}
]
}
},
{
title: "Post Title Two",
categories: {
data: [
{
id: 2,
name: "Category Name 1"
},
{
id: 3,
name: "Category Name 2"
}
]
}
}
]
and I want to grab all the categories for each post and display them using Vue. So what I have currently is:
<div v-for="post in posts">
<div>{{ post.categories.data }}</div>
</div>
In that {{ post.categories.data }} I am trying to display the category name from the JSON object. When I use what I have above the whole array is displayed in the div. When I try to do something like
{{ post.categories.data.name }}
or
{{ post.categories.data[0].name }}
I don't display the name of the category. I would really like to display the name of every category a post has, but can't seem to get it to display correctly.
EDIT: Also posts is the data property I am using in VueJS and am setting the JSON object to become that property.
You should use map method in conbination with destructuring.
<div v-for="post in posts">
<div>{{ post.categories.data.map(({name}) => name).join(' ') }}</div>
</div>

Ionic 2 / Angular 2 Fetching Data from Object within Array

I am trying to build a simple accordion in Ionic 2 by pulling data from a json file.
I can iterate through the category and subcategories items to list those, however once a subcategory is clicked, I am not able to fetch the data from the subcategory object and display it (subcategory title) on a detail page. I have looked at many different tutorials/forums but couldn't find how to do this anywhere.
I imagine it is not just an issue with the path but I might need to iterate through the subcategory objects further?
json
{
"results": [
{
"category": "Category 1",
"subCategory": [
{
"title": "subCategory 1.1",
"word": "hello"
},
{
"title": "subCategory 1.2",
"word": "hello"
}
]
},
{
"category": "Category 2",
"subCategory": [
{
"title": "subCategory 2.1",
"word": "hello"
},
{
"title": "subCategory 2.2",
"word": "hello"
}
]
}
]
}
home.html
<ion-header>
<ion-navbar color="primary">
<ion-title>Categories</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item *ngFor="let item of (items | async)?.results">
{{ item.category }}
<div *ngFor="let subItem of item.subCategory">
<button (click)="openDetails(item)">{{ subItem.title }}</button>
</div>
</ion-item>
</ion-list>
</ion-content>
home.ts
export class HomePage {
items: any;
subcategories: any;
constructor(public navCtrl: NavController, public http: Http) {
this.items = this.http.get("assets/data/results-data.json").map(res => res.json());
}
openDetails(item) {
this.navCtrl.push('FilmDetailsPage', {item: item});
}
}
detail.html
<ion-header>
<ion-navbar color="primary">
<ion-title>{{ item.subCategory.title }}</ion-title> // NOT WORKING
</ion-navbar>
</ion-header>
You need to send the subItem i.e. each subcategory and not the item to openDetails() function.
<button (click)="openDetails(subItem)">{{ subItem.title }}</button><!-- here -->
In your details.html,
you can access as
<ion-title>{{ subItem.title }}</ion-title> <!-- make sure the parameter in ts file has name subItem. -->

Categories

Resources