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
Related
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
I am seeking the below result with nested JSON. I am not able to retrive/call keys and values in template dynamically. Refrence link is attached for detail veiw
Angular Code
let checklist = {
"CS": [
{
"id": "1",
"name": "A"
},
{
"id": "2",
"name": "B"
},
{
"id": "3",
"name": "C"
}
],
"Comment": [
{
"id": "1",
"name": "D"
},
{
"id": "2",
"name": "E"
},
{
"id": "3",
"name": "F"
}
]
}
<div *ngFor="let item of Checklist | Key">
{{key}}
<div>{{item}}</div>
</div>
Desired Result
Use keyvalue pipe to loop over Objects within template, Use some css to modify the display but a code like below will serve your need.
<div *ngFor="let item of checklist | keyvalue">
<div>
{{item.key}}
</div>
<div>
<p *ngFor="let eachValue of item.value">
{{eachValue.name}}
</p>
</div>
</div>
https://stackblitz.com/edit/angular-jgwk8n?file=src%2Fapp%2Fapp.component.html
Edit
For angular version < 6, keyvalue pipe doesn't exist. You can create your own custom pipe, maybe like:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'customKeyvalue',
pure: true // keyvalue pipe is actually impure, which means this value would be false
})
export class CustomKeyvaluePipe implements PipeTransform {
transform(inputOb: any): any {
let returnVal = [];
for (let eachKey in inputOb) {
returnVal.push({key: eachKey, value: inputOb[eachKey]})
}
return returnVal
}
}
Now in case your Object changes dynamically without changing its original reference then you would have to make the above pipe as impure (pure: false). This has a downside of being triggered in every change detection.
https://stackblitz.com/edit/angular-jgwk8n?file=src%2Fapp%2Fapp.component.html
You can use Object.keys to get the keys of the object.
This is your component:
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
public checklist: any;
public ObjectKeys = Object.keys;
name = 'Angular';
ngOnInit() {
this.checklist = {
"CS": [
{
"id": "1",
"name": "A"
},
{
"id": "2",
"name": "B"
},
{
"id": "3",
"name": "C"
}
],
"Comment": [
{
"id": "1",
"name": "D"
},
{
"id": "2",
"name": "E"
},
{
"id": "3",
"name": "F"
}
]
};
}
}
This is the HTML:
<table border="1">
<tbody>
<tr *ngFor="let key of ObjectKeys(checklist)">
<td colspan="2" style="border-right-style: solid; border-width: 1px;">
{{ key }}
</td>
<td>
<div *ngFor = "let entry of checklist[key]">
{{ entry.name }}
</div>
</td>
</tr>
</tbody>
</table>
This is the result:
You can add CSS to make it look better, but you get the gist now :)
This is the StackBlitz link which you can edit.
The trick here is to use the display: inline-block and vertical-align: top.
It's similar to xyz example.
<div *ngFor="let item of checklist | keyvalue" >
<div style="display:inline-block;">
{{item.key}}
</div>
<div style="display:inline-block;vertical-align: top;">
<div *ngFor="let eachValue of item.value" >
{{eachValue.name}}
</div>
</div>
</div>
Example: https://angular-hzuexu.stackblitz.io
I have a GET method that returns the following JSON on route localhost:3000/documents
[{
"id": "5b48bffc644fca001419769c",
"names": [{
"name": "bob"
},
{
"name": "stan"
}
],
"cities": [{
"city": "London"
},
{
"city": "Madrid"
}
]
}]
I want to concatenate all the names and cities and display them inside HTML tags with Angular.
<p> id </p>
<p> concatenated names here </>
<p> concatenated cities here </>
Is it possible to access documents and concatenate the array values using ngFor?
I have the following component:
import {Component, OnInit} from '#angular/core';
import {DocumentService} from '../services/document.service';
import {Document} from './document.model';
#Component({
selector: 'app-document',
templateUrl: './document.component.html',
styleUrls: ['./document.component.css']
})
export class DocumentComponent implements OnInit {
documents: Document[];
constructor(private documentService: DocumentService) {
}
ngOnInit() {
this.getDocuments();
}
getDocuments(): void {
this.documentService.getDocuments()
.subscribe(documents => this.documents = documents);
}
}
And the following service:
import {Injectable} from '#angular/core';
import {HttpClient, HttpHeaders} from '#angular/common/http';
import {Document} from '../document/document.model';
#Injectable({providedIn: 'root'})
export class DocumentService {
private urlDocuments = 'localhost:3000/documents';
constructor(private http: HttpClient) {
}
getDocuments() {
return this.http.get<Document[]>(this.urlDocuments);
}
}
My document model is:
export class Document {
public _id: string;
public names: [{ name: string }];
public cities: [{ city: string }];
constructor(_id: string, names: [{ name: string }],
cities: [{ city: string }]]) {
this._id = _id;
this.cities=cities;
this.names= name;
}
}
I have the solution, but you need to modify your object.
You have to override toString method for cities and names in your model:
test= [{
"id": "5b48bffc644fca001419769c",
"names": [{
"name": "bob",
toString: function(){return this.name;}
},
{
"name": "stan",
toString: function(){return this.name;}
}
],
"cities": [{
"city": "London",
toString: function(){return this.city;}
},
{
"city": "Madrid",
toString: function(){return this.city;}
}
]
}];
HTML section will be look like:
<div *ngFor="let t of test">
<p> {{t.id}}</p>
<p> {{t.names.join(",")}}</p>
<p> {{t.cities.join(",")}} </p>
</div>
Output:
5b48bffc644fca001419769c
bob,stan
London,Madrid
Assume your documents data is getting no problem from server, then try this HTML code below:
<div *ngFor="let d of documents">
<p>Id: {{d.id}}</p>
<p>Names: <span *ngFor="let dd of d.names">{{dd.name}},</span></p>
<p>Cities: <span *ngFor="let dd of d.cities">{{dd.city}},</span></p>
</div>
You just need to use an *ngFor in order to iterate over the documents and then two *ngFors for iterating over the names and the cities like this (StackBlitz Demo):
ts:
documents = [{
"id": "5b48bffc644fca001419769c",
"names": [{"name": "bob"},{"name": "stan"}],
"cities": [{"city": "London"},{"city": "Madrid"}]
},{
"id": "5b48bffc644fca001419769cde",
"names": [{"name": "Jon"},{"name": "Doe"}],
"cities": [{"city": "Barcelona"},{"city": "Saragoza"}]
}
];
html:
<div *ngFor="let doc of documents; let last = last"> <!-- iterate over all documents, let last = last is optional -->
<p>Id: {{doc.id}}</p>
<!-- iterate over all names (n) for every document (doc) -->
<p>Names: <span *ngFor="let n of doc.names; last as lastName">{{n.name}}{{lastName ? '': ','}} </span></p>
<!-- iterate over all cities (c) for every document (doc) -->
<p>Cities: <span *ngFor="let c of doc.cities; last as lastCity">{{c.city}}{{lastCity ? '': ','}} </span></p>
<!-- optional , this will add a separator between documents-->
<hr *ngIf="!last"/>
</div>
Output:
I want to do following:
Show all the html elements on the page based on some conditions,
my understanding was i can use ng-if.
If employeeList is empty then do i need to create another copy of the inner elements to make sure it shows on the page
ng-if prints both divs and spans which only one should be printed my html is this
html:
<div class="container" ng-controller="profileController" ng-init="loadProfilesData()">
<div ng-repeat="p in profileData">
<div>{{p.company}}</div>
<div>{{p.department}}</div>
<div ng-repeat="emp in p.employeeList"></div>
<div ng-if="emp.Tag== 'Devo100'" gauge-chart class="gauge" id="Devo100-{{p.Id}}" value=p.Value*100></div>
<div ng-if="emp.Tag!= 'Devo100'" gauge-chart class="gauge" id="Devo100-{{p.Id}}" value=0></div>
<span ng-if="emp.Tag== 'Devo102'">
{{ p.Value | date: "hh:mm:ss" }}
</span>
<span ng-if="emp.Tag== 'Devo102'">
0
</span>
</div>
</div>
</div>
my json is following
profileData: [
{
ID: "1",
metricStatList: [{"Value":0.003,"Stat":{"parameter":0,"Name":"test0","Tag":"Devo100"}},
{"Value":0.004,"Stat":{"parameter":0,"Name":"test1","Tag":"Devo101"}},
{"Value":0.005,"Stat":{"parameter":0,"Name":"test2","Tag":"Devo102"}}],
comapny: "MSDFT",
department: "Sales"
},
{
ID: "2",
metricStatList: null,
comapny: "MSDFT",
department: "HR"
},
{
ID: "3",
metricStatList: [{"Value":0.003,"Stat":{"parameter":0,"Name":"test0","Tag":"Devo100"}},
{"Value":0.004,"Stat":{"parameter":0,"Name":"test1","Tag":"Devo101"}}],
comapny: "MSDFT",
department: "Development"
},
{
ID: "4",
metricStatList: [{"Value":0.1,"Stat":{"parameter":0,"Name":"test2","Tag":"Devo102"}},
{"Value":0.25,"Stat":{"parameter":0,"Name":"test1","Tag":"Devo101"}}],
comapny: "MSDFT",
department: "Finance"
},
{
ID: "5",
metricStatList: [{"Value":0.233,"Stat":{"parameter":0,"Name":"test0","Tag":"Devo100"}}],
comapny: "MSDFT",
department: "Accounts"
}
]
How to pass array of values as filter in angularjs
My scenario
cuisines json: ["food", "Alcohol","Thai"]
catorigeres json :["home", "office","school"]
values with cuisines and categories :
[{
"_id": "1",
"businessTypeName": "Pizza Hut",
"cus_name": ["food","Thai"],
"cat_name": ["home", "school"],
}, {
"_id": "2",
"businessTypeName": "Chicken Hut",
"cus_name":["Alcohol","Thai"],
"cat_name": ["office", "home"],
}, {
"_id": "3",
"businessTypeName": "Fish Hut",
"bussiness_url": "/dist/images/loop_image_sample_3.png",
"cus_name": ["Thai"],
"cat_name": ["office", "school"],
}]
cuisines and categories are of in checkbox if i click anyone it will append the array of values to {{selected}}
my question is how to filter values in {{selected}} to listing_loop div
my plunker demo
I don't think you can do that in html alone.
You can add a filtering function to the scope:
$scope.customFilter = function(value, index, array) {
// make sure `value.id` is a string
return ["food","Thai","Alcohol"].indexOf(value.id);
}
and using like this in HTML
<div ng-repeat="set in get | filter:customFilter"></div>