Get data from nested json in Angular - json

Im trying to iterate over an array but page is displaying [ object Object] instead. How can I get data.id of my example?
Service:
return this._http.get<CustomersList[]>(this.apiUrl,{ headers: reqHeader });
My json looks like this:
[ {"current_page":1,"data":[{"id":25},{"id":26}] }]
And here is my component:
customerslist$: CustomersList[];
return this.customerdataService.getCustomersList().subscribe(data => this.customerslist$ = data);
Would be great if anybody can help me?

The data property is an array contained in an array. You either need two *ngFor directives
<ng-container *ngFor="let customer of customerslist$">
<ng-container *ngFor="let item of customer.data">
{{ item.id }}
</ng-container>
/ng-container>
Or if you're sure the customerslist$ array will always contain only one element, you could access the first element directly.
<ng-container *ngFor="let item of customerslist$[0].data">
{{ item.id }}
</ng-container>
Also if you're aren't using the this.customerList$ in the controller, you could skip the subscription in the controller and use the async pipe in the template. It takes care of any potential memory leak issues due to open subscriptions.
Contoller
customerslist$: Observable<CustomersList[]>; // <-- typeof `Observable`
ngOnInit() {
this.customerslist$ = this.customerdataService.getCustomersList(); // <-- don't subscribe yet
}
<ng-container *ngIf="(customerslist$ | async) as customerslist">
<ng-container *ngFor="let customer of customerslist">
<ng-container *ngFor="let item of customer.data">
{{ item.id }}
</ng-container>
</ng-container>
</ng-container>
By convention, variable names suffixed with a dollar sign (customerlist$) are used to denote observables.

If you are using Observable $ sign at the end of variable denotes observable,
in that case you do not need to subscribe only return value, in template you can subscribe using async pipe which automatically unsubscribe as well to prevent memory leak and a recommended approach.
Here we assume we are only taking first element of array that why directly accessing it giving first index, otherwise we need to iterate that array in template as well.
customerslist$: Observable<CustomersList[]>;
this.customerslist$ = this.customerdataService.getCustomersList()
.pipe(map(res) => res[0].data));
In template use async pipe to subscribe
<ng-container *ngFor="let data of customerslist$ | async">
<span> {{ data.id }} </span>
</ng-container>
WITHOUT OBSERVABLE
customerslist: CustomersList[];
this.customerdataService.getCustomersList()
.subscribe((res) => this.customerslist = res[0].data));
In template
<ng-container *ngFor="let data of customerslist">
<span> {{ data.id }} </span>
</ng-container>

Related

Displaying object into HTML in Angular

sorry for the noob question.
I created an http request and retrieved some pokemon data and put it in an object called pokemon, like so:
export class AppComponent implements OnInit{
title = 'Pokedex';
apiURL = 'https://pokeapi.co/api/v2/pokemon/1';
pokemon = {};
constructor(private http: HttpClient){}
ngOnInit(): void{
this.http.get(this.apiURL).subscribe(data =>{
const pokemon = {
name: data['name'],
id: data['id'],
abilities: data['abilities'].map( ability => ability['ability']['name']),
types: data['types'].map( type => type['type']['name']),
image: data['sprites']['front_default']
}
console.log(pokemon);
When I console log the object, it outputs in the console fine.
However, when I try to display it in an html {{ pokemon }} it just returns [object, Object]
How can I get around this?
I have tried the methods suggested below.
{{pokemon.name}}, {{pokemon[name]}} and {{pokemon?.name} display a blank page.
{{ pokemon | json }} returns an empty object, in the form of {}.
Am I perhaps doing something else wrong?
You need to use the json pipe
<pre>{{ pokemon | json }}</pre>
OR
<div> Id: {{ pokemon.id }} </div>
<div> Name: {{ pokemon.name }} </div>
<div> Abilities:
<ul>
<li *ngFor="let ability of pokemon.abilities"> {{ ability }}</li>
</ul>
</div>
<div> Types:
<ul>
<li *ngFor="let type of pokemon.types"> {{ types }}</li>
</ul>
</div>
call property as {{pokemon?.name}}
You can't use object directly. You have to access object properties by either . (Dot) notation or object[property] way.
In your case, if you want to use the property of name then use
{{ pokeman.name }}
or
{{ pokeman[name] }}

Angular material table, how to format output

I am working on Angular module, and I am fetching data from web api.
I am displaying web api response in a mat table.
I have a list of strings that I want to display with line break.
To do that I am formatting the response and adding <span> and <br> tags.
But the output is displaying the <span> and <br> tags also.
Here is my code.
const data:any=[];
this.receiveService.get(this._parentLocID).subscribe(
res => {
res.forEach( g1=>{
let nstatus=[];
let newstatus=g1.status;
newstatus.forEach(
res1=>{
nstatus.push('<span>'+res1+'</span>'+'<br>');
}
);
g1.status=nstatus;
data.push(g1);
});
const resultData: any = data;
this.dataSource.data = resultData;
My objective is simple, I want the values 'completed','In progress' and 'Queued' in separate lines.
In order to bind HTML content you should use [innerHTML] property, you can find more details in this article
https://www.google.com/amp/s/blog.fullstacktraining.com/binding-html-with-angular/amp/
I fell in your scenario instead of building HTML in typescript you can push only string values and use ngFor in HTML and bind it to {{content}} something like that will be a better option.
I have solved it this way. It was much simpler than I thought.
I had to put *ngIf within mat-cell. And for each item in the array,I put an "br" tag at the end of each item.
<mat-cell *matCellDef="let element">
<p class="font-weight-600 text-center" *ngIf="columns.key=='Status'">
<span *ngFor="let item of element[columns.value]">
{{ item }}
<br>
</span>
</p>
<p class="font-weight-600 text-center" *ngIf="columns.key!='Status'">
{{element[columns.value]}}
</p>
</mat-cell>
also, I removed this part from .ts file.
res.forEach( g1=>{
let nstatus=[];
let newstatus=g1.status;
newstatus.forEach(
res1=>{
nstatus.push('<span>'+res1+'</span>'+'<br>');
}
);
g1.status=nstatus;
data.push(g1);
});
so the .ts is
this.receiveService.get(this._parentLocID).subscribe(
res => {
const resultData: any = res;
this.dataSource.data = resultData;
}
that solved the issue.

Problem with managing my *ngFor for array object

My object is:
{
"name": "OCA Netflix",
"workflowNames": [
"OCA-Netflix-Action",
"OCA-Netflix-Action-v2"
]
}
When I use ngFor in my html i use:
{{ usecase.workflowNames }} and I see elements separated by ",".
How can i insert in my code to see elements in a column?
EXAMPLE:
Not: OCA-Netflix-Action, OCA-Netflix-Action-v2
But:
OCA-Netflix-Action
OCA-Netflix Action-v2
You can use *ngFor directive with ng-container and add br tag to provide a new line.
<ng-container *ngFor="let v of usecase.workflowNames; let l = last;">
{{v}}<br *ngIf="!l"/>
</ng-container>
Use below code in html
<div *ngFor="let item of usecase.workflowNames;let i=index;">
<div>
{{item}}<br/>
</div>
</div>

How to iterate over single character in a string

How can I iterate a string using the *ngFor?
I have a string with binary code (e.g. 0010) and dependendig on a single bit I have to show a different icon.
<div class="row" *ngFor="let item of subscribedCommandBus2Easy; let i = index">
<span class="numberCircleBus2Easy col-md-2">
{{item}}
</span>
<i *ngFor="let num of commandsDecimal">
<i ng-repeat="let el in num">
<span [ngClass]="el =='0' ? 'off-icon' : 'on-icon'">
//is this the way I access the single character?
</span>
</i>
</i>
</div>
I tried this code but it does not work.
commandsDecimal is my array of binary string. I want to loop commandsDecimal at index i (suppose the element is 1010) and if the character at position y is 0 I have to show an icon otherwise the other icon and so on...
Any suggestion?
The best way is to do a split on your string. With a custom pipe:
#Pipe({
name: 'split'
})
export class SplitPipe implements PipeTransform {
transform(value: any, args?: any): any {
return value.split('');
}
}
And then iterate over it. like that:
<div *ngFor="let item of myString">
<div *ngFor="let num of item | split item">
// access num
</div>
</div>
Example: https://stackblitz.com/edit/angular-8bkywr
In your component typescript
function getSplit(string) {
return string.split('').map(number)
}
In the template
*ngFor="let num of getSplit(commandsDecimal)"
You can do this without the need for any code in your component. Also ng-repeat is AngularJS syntax, not Angular 2+. In Angular 2+, ngFor is used to iterate in the HTML.
<ng-container *ngFor="let num of commandsDecimal">
<i *ngFor="let el of num.split('')" [ngClass]="el === '0' ? 'off-icon' : 'on-icon'"></i>
</ng-container>

Reference ngFor value in component

I have a nested ngFor statement. I need to retrieve the value of my first ngFor on button click.
I have tried the following:
use template reference variable
use attribute binding
use Input decorator
This is my code:
<mat-expansion-panel *ngFor="let item of Datasource;">
<mat-expansion-panel-header style="display:flex" class="mat-row">
{{item.Header}}
</mat-expansion-panel-header>
<mat-selection-list [(ngModel)]="selectedOptions">
<mat-list-option *ngFor="let line of item.match; let i= index;" [value]="line">
<div class="container-name">
<div class="col-6">{{i}} - {line.user.Name }} vs {{ line.user.Address }}</div>
</mat-list-option>
</mat-selection-list>
<div style="text-align:center; padding: 20px">
<button mat-raised-button color="primary" (click)="submit()" type="submit">Add</button>
</div>
</mat-expansion-panel>
Can this be achieved?
Well, you need to clone that object properties first. As that object is linked to the template, when you manipulate it, it is manipulated on template too. You can use var obj = Object.assign({}, actual obj) and then do the manipulation on obj instead of actual one. Then it will not get affected in template. Hope it helps.