How to fetch a particular data from database using Angular Observer - html

In the input box when I enter 'Title' i should get the list of the title but when I run this I get the list of [object Object][object Object][object Object]...
Here is the API
https://jsonplaceholder.typicode.com/posts
I need to get the particular information
HTML
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
<input type="text" #name>
<button class="btn btn-primary" (click)="onGet(name.value)">Add Server</button>
<p>{‌{ servers }}</p>
</div>
</div>
</div>
COMPONENT.TS
import { Component } from '#angular/core';
import {ServerService} from "./server.service";
#Component({
selector: 'app-list',
templateUrl: './list.component.html',
styleUrls: ['./list.component.css'],
providers: [ServerService]
})
export class ListComponent {
servers = [];
constructor(private serverService: ServerService) {}
onGet(name: string) {
this.serverService.getServers( name )
.subscribe(
(servers: any[]) => this.servers = servers,
(error) => console.log(error)
);
}
}
SERVICE.TS
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
import {map} from "rxjs/operator/map";
#Injectable()
export class ServerService {
constructor(private _http: Http) {}
getServers(name: string) {
console.log(name);
return this._http.get('https://jsonplaceholder.typicode.com/posts' )
.map(
(response: Response) => {
const data = response.json();
console.log(data)
return data.name;
}
)
}
}
Please help me with this.

Update you service as following:
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
import {map} from "rxjs/operator/map";
#Injectable()
export class ServerService {
constructor(private _http: Http) {}
getServers(name: string) {
console.log(name);
return this._http.get('https://jsonplaceholder.typicode.com/posts' )
.map(
(response: Response) => {
const data = response.json();
console.log(data)
return data;
}
)
}
}
Here data is returned instead of data.name. As data is an array of object there is no property "name" in data. "name" is an property of it's item.
And template should be:
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
<input type="text" #name>
<button class="btn btn-primary" (click)="onGet(name.value)">Add Server</button>
<div *ngFor="let server of servers">
<p *ngIf="name.value == 'title'">{{server.title}}</p>
<p *ngIf="name.value == 'id'">{{server.id}}</p>
<p *ngIf="name.value == 'userId'">{{server.userId}}</p>
<p *ngIf="name.value == 'body'">{{server.body}}</p>
</div>
</div>
</div>
</div>
Then it will show the list of title.

The value you try to interpolate in your template is an Array (servers). When you try to interpolate reference type objects in Angular templates, you will get the string representation of them (interpolation uses toString()), so, [object Object] or [object Array]. If you want to see the object in plain text inside a template, consider using the json pipe, like this: <p>{‌{ servers | json }}</p>, but most probably you will want to use ngFor and unwrap the objects inside the array, like this, probably: <p *ngFor="let server of servers">{{ server.title}}</p>, for example. Read more about json pipe and ngFor here and here

Related

Displaying Data without *Ngfor

I'm trying to display data without using a ngFor loop. It works perfectly but shows all of the quote information from multiple customers. The CSS is laid out in a way that has the discount div next to the customerinfo div Here is the HTML
<hr />
<div class="info">
<div id="CustomerInfoInline" *ngIf="quotes" >
<div *ngFor="let q of quotes">
<h6>Name: {{q.firstName}} {{q.lastName}}</h6>
<h6>Address: {{q.address}}</h6>
<h6>City, State, Zip: {{q.city}}, {{q.state}}, {{q.zip}}</h6>
<h6>SSN: {{q.SSN}}</h6>
<h6>DOB: {{q.dateOfBirth}}</h6>
<h6>Email: {{q.email}}</h6>
<h6>Prev. Carrier: {{q.previousCarrier}}</h6>
<h1>-----------------------------------------------------------------------------------------------</h1>
</div>
</div>
<div *ngIf="quotes">
<div id="CustomerDiscountsInline" *ngFor="let q of quotes">
<h6 id="customerBold">Customer Discounts</h6>
<h4 id="DiscountsID">discounts will be applied here</h4>
</div>
</div>
</div>
<hr />
and the respective TS
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { environment } from '#environments/environment';
import { Quote } from '#app/_models/quote';
import { Router } from '#angular/router';
#Component({
selector: 'app-quote-summary',
templateUrl: './quote-summary.component.html',
styleUrls: ['./quote-summary.component.css']
})
export class QuoteSummaryComponent implements OnInit {
apiUrl: string = environment.apiUrl
quotes: Quote[]
//TODO: implement submitted quote view later
//submittedQuotes: Quote[]
constructor(private http: HttpClient, private router: Router) { }
ngOnInit(): void {
this.getQuotes()
}
// #region API Calls
getQuotes() {
var httpRequest = this.http.get<Quote[]>(`${this.apiUrl}/quotes`)
httpRequest.subscribe(returnedQuotes => {
this.quotes = returnedQuotes
})
}
}
If you need to show only one customer you can use indexer for quotes like quotes[0]:
Don't forgot to check quotes.length > 0:
<div class="info">
<div id="CustomerInfoInline"
<div *ngIf="quotes && quotes.length > 0">
<h6>Name: {{quotes[0].firstName}} {{quotes[0].lastName}}</h6>
<h6>Address: {{quotes[0].address}}</h6>
....
</div>
</div>
</div>

dispay json data in ngfor loop in angular (data from firebase)

In my Angular code, I am getting data from a firebase database through an Http get request and when I try to display the result with an ngfor loop, I have an error message. This example was replicated from a tutorial and it worked for him. Where is the problem and how could I make it work? Thanks for helping!
I use a service to get data here is the code:
import {Http} from '#angular/http';
import { Injectable } from '#angular/core';
import {Response} from "#angular/http";
import {map} from 'rxjs/operators';
#Injectable()
export class ServerService {
constructor(private http:Http){}
StoreServers(servers:any[]){
return this.http.post('https://ng-http-a5718.firebaseio.com/data.json',servers);
}
GetServers(){
return this.http.get('https://ng-http-a5718.firebaseio.com/data.json').pipe(map(
(res:Response) =>{
const dataserver = res.json() as any[];
for(const server of dataserver ){
server.name='fetched_server'+server.name
}
return dataserver;
}
)
)
}
}
Here is the .ts code of the component where I try to display the data:
import { Component } from '#angular/core';
import { ServerService } from './server.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private ServerService : ServerService){}
servers = [
{
name: 'Testserver',
capacity: 10,
id: this.generateId()
},
{
name: 'Liveserver',
capacity: 100,
id: this.generateId()
}
];
onAddServer(name: string) {
this.servers.push({
name: name,
capacity: 50,
id: this.generateId()
});
}
private generateId() {
return Math.round(Math.random() * 10000);
}
OnSave(){
this.ServerService.StoreServers(this.servers).subscribe(
(Response)=>(console.log(Response)),
(Error)=>(console.log(Error))
)
}
OnGet(){
this.ServerService.GetServers().subscribe(
(data) => { this.servers=data}
,
(Error)=>{
return (console.log(Error));
}
)
}
}
Here is the html code of the component where I try to display the data:
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
<input type="text" #serverName>
<button class="btn btn-primary" (click)="onAddServer(serverName.value)">Add Server</button>
<hr>
<button class="btn btn-primary" (click)='OnSave()'>Save servers</button>
<button class="btn btn-primary" (click)='OnGet()'>Get servers</button>
<br>
<ul class="list-group" *ngFor="let server of servers">
<li class="list-group-item">{{ server.name }} (ID: {{ server.id }})</li>
</ul>
</div>
</div>
</div>
And finally here it is the error message I get:
enter image description here
this.server expecting Array in onGet() method but getting Object from firebase with the unique key. so you can modify onGet() method in following:
OnGet(){
this.ServerService.GetServers().subscribe(
(data) => {
const keys = Object.keys(data);
const firstKey = keys[0];
this.servers = data[firstKey]; // get the inside array
}
,
(Error)=>{
return (console.log(Error));
}
)
}

Angular, trouble using ngIf, async and Observable to wait until data is ready to display content

I am new to Angular and I am stuck. I can't seem to get this to work and I think I'm just making some mistakes on how I'm implementing the Observable. Currently I am using a local json file as my data source, but in my main project I will connect to an external API. I have stripped everything down to make it as basic as possible and still no luck.
Here's campaign.component.ts
import { Component, OnInit } from '#angular/core';
import { Observable } from 'rxjs';
import { CampaignService } from '../campaign.service';
#Component({
selector: 'app-campaign',
templateUrl: './campaign.component.html',
styleUrls: ['./campaign.component.css']
})
export class CampaignComponent implements OnInit {
$campaign: Observable<any>;
constructor(
private campaignService: CampaignService
) {}
ngOnInit(): void {
this.getCampaign();
}
getCampaign(): void {
this.campaignService.getCampaign().subscribe((data) => {
this.$campaign = data;
console.log(this.$campaign);
});
}
}
Here's the template html, campaign.component.html
<div *ngIf="($campaign | async) as campaign; else loading">
<!--this never loads-->
{{campaign.shortName}}
</div>
<ng-template #loading>
<!--this is all I see-->
Loading stuff in ngIf...
</ng-template>
<br>
<br>
<!--this works so I know the data loads and that my json file is formatted correctly-->
<p>Outside of ngIf works: {{$campaign.shortName}}</p>
Here's the service, campaign.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '#angular/common/http';
import { Observable, of } from 'rxjs';
import { map} from 'rxjs/operators';
const endpoint = 'assets/api.json';
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
#Injectable()
export class CampaignService {
constructor(private http: HttpClient) {}
private extractData(res: Response) {
let body = res;
return body || { };
}
getCampaign(): Observable<any> {
const url = endpoint;
console.log(url);
return this.http.get(url).pipe(
map(this.extractData));
}
}
Thanks for taking the time to help with this.
getCampaign(): void {
this.campaignService.getCampaign().subscribe((data) => {
this.$campaign = data;
console.log(this.$campaign);
});
}
The above assigns the data value to the property this.$campaign but you've declared that property to be an observable.
<div *ngIf="($campaign | async) as campaign; else loading">
<!--this never loads-->
{{campaign.shortName}}
</div>
$campaign is not an observable so the async pipe resolves to undefined. The condition is always false.
<!--this works so I know the data loads and that my json file is formatted correctly-->
<p>Outside of ngIf works: {{$campaign.shortName}}</p>
The above works because $campaign was assigned the data value.
<p>Outside of ngIf works: {{($campaign | async)?.shortName}}</p>
You should always use async in the template for observables.
You can simplify the component by assigning the observable in the constructor.
constructor(private campaignService: CampaignService) {
this.$campaign = campaignService.getCampaign();
}
Alternatively, you don't have to use async if you subscribe and assign the data.
<div *ngIf="campaign; else loading">
<!--this never loads-->
{{campaign.shortName}}
</div>
<p>Outside of ngIf works: {{campaign?.shortName}}</p>

Angular5 *ngfor not working, but there is no error

I'm facing a problem with Angular at the moment.
I want to read data from my server API and want to display it with *ngfor in a html document.
I can receive the data from the API, but i can't display it.
I took the example code from the tour of heroes tutorial and changed it:
The data gets through to my angular app. I can console.log it and see it in chrome development console.
I tried to display other data that I get from my api and it is working. You can see the data commented out in heroes.components.ts.
Who can help me with this?
If you want to see some more of the code like imports please tell me. But i guess everything needed imported as there are no error messages, i can get the data from my api and i can display some data (sadly not the data i need).
I tried several ideas to solve this from some other posts, but can't get it working.
Here are some Code Snippets:
This is my hero.service.ts
imports...
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { HttpResponse } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { catchError, map, tap } from 'rxjs/operators';
import { Hero } from '../model/hero';
import { MessageService } from '../message.service';
import { Response } from '#angular/http/src/static_response';
getHeroes(): Observable<Hero[]> {
console.log("GET HEROES IN HEROES.SERVICE");
return this.http.get<Hero[]>(this.heroesUrl)
.pipe(
tap(Hero => console.log(`fetched heroes: `)),
catchError(this.handleError('getHeroes', []))
);
//I also tried to just use return this.http.get<Hero[]>(this.heroesUrl);
This is my
heroes.components.ts
import { Component, OnInit } from '#angular/core';
import { Hero } from '../../model/hero';
import { HeroService } from '../hero.service';
import { CommonModule } from '#angular/common';
import { Pipe } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import { Response } from '#angular/http/src/static_response';
// For use of map
import 'rxjs/Rx';
#Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
heroes: Observable<Hero[]>;
// I tried to display some data
// heroes: any[] = [
// {
// "name": "Douglas Pace"
// }
// ];
constructor(private heroService: HeroService) { }
ngOnInit() {
this.getHeroes();
// undefined
console.log("ONINIT");
console.log(this.heroes);
}
getHeroes(): void {
console.log("GET HEROES IN HEROES.COMPONENT");
this.heroService.getHeroes()
.subscribe(
function(response: Hero[]) {
console.log("RESPONSE IN HEROES COMPONENT");
console.log(this.heroes);
var res = response["data"];
// console.log(res.json());
this.heroes = res;
console.log(this.heroes);
console.log(response["data"]);
},
function(error) {
console.log("Error happened" + error)
},
function() {
console.log("the subscription is completed")
//This shows me the right data.
console.log(this.heroes[5].id);
console.log(this.heroes[5].titel);
console.log(this.heroes[5].name);
console.log(this.heroes[5].vorname);
}
);
}
My html file:
<h2>My Heroes</h2>
<!-- <input type=text ng-model="hero"> -->
// I gave it a try with and without *ngIf="heroes"
<!-- only show the list IF the data is available -->
<div *ngIf="heroes">
<h3>Heroes are available and are displayed</h3>
<li *ngFor="let hero of heroes">
{{hero.name}}
</li>
</div>
<button (click)="button()">
Suchen
</button>
<div *ngIf="heroes">
<table class="heroes">
<tr>
<th>Id</th>
<th>Titel</th>
<th>Nachname</th>
<th>Vorname</th>
</tr>
//I tried async as the data is maybe not available from the
beginning. Also tried async on hero as heroes is created on init
and single heros are added with the function getHeroes();
<tr *ngFor='let hero of heroes | async'>
<a routerLink="/detail/{{hero.id}}">
<td>{{hero.id}}</td>
<td>{{hero.titel}}</td>
<td>{{hero.name}}</td>
<td>{{hero.vorname}}</td>
</a>
<button class="delete" title="delete hero"
(click)="delete(hero)">x</button>
</tr>
</table>
</div>
<pre>{{heroes | json}}</pre>
If got a hero interface. Should be my model. Only Last and First name are needed.
export interface Hero {
id?: string;
name: string;
titel?: string;
vorname: string;
}
The JSON I returned from my API. Online Json formatter says it is valid json.
{"status":"Success","data":
[{"id":"36","name":"Hero","vorname":"Super","titel":"Dr.",},
{"id":"34","name":"Man","Spider":"Ines","titel":""}],
"message":"Retrieved all HEROES"}
this.heroService.getHeroes()
.subscribe(
function(response: Hero[]) { }
Your problem could be here. Your response is an object with (let's say, interface):
interface DataResponse {
success: string;
data?: Hero[];
}
Because you set response: Hero[] and there's no data property in your Hero interface, response["data"] returns null and you'll never get your data. If you run response.data, you'll probably get an error saying data is not defined in Hero etc...
Change to the following:
this.heroService.getHeroes()
.subscribe((response: DataResponse) => {
this.heroes = response["data"];
});
Your code seems to be ok but i see an error in your json format here
"titel":"Dr.",},
try to remove the comma after Dr and give it a try
"titel":"Dr."},

How to capture and display data from Observable?

I have a component named 'customer.component.ts'.
In this component's view there is a button called 'Search'.
What I I am doing is calling a web api method on this 'Search' button click which brings the data from sql db.
For this, I have a customer.service.ts file in which I wrote the below code -
import { Injectable } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { Observable } from 'rxjs';
import "rxjs/add/operator/map";
import 'rxjs/add/operator/toPromise';
import { Customer, CustomerContact, CustomerHeaderAndContactsResponse, CustomerSearchRequestObjectClass, CustomerHeaderAndContactsResponse_Read } from '../models/customer';
#Injectable()
export class CustomerService {
constructor(private _http: Http) {
}
baseUrl: string = 'http://localhost/SampleApi/api/Customer/';
searchCustomers(custReqObj: CustomerSearchRequestObjectClass): observable<CustomerHeaderAndContactsResponse_Read> {
let headers = new Headers();
headers.append('Content-Type', 'application/json; charset=utf-8');
return this._http.post((this.baseUrl + 'search-customer'), JSON.stringify(custReqObj), { headers: headers }).map(res => res.json());
}
}
my customer.component.ts has the search click function -
import { Component, OnInit } from '#angular/core';
import { strictEqual } from 'assert';
import { ChangeDetectorRef } from '#angular/core';
import { stringify } from '#angular/core/src/facade/lang';
import { Customer, CustomerContact, CustomerHeaderAndContactsResponse_Read } from '../models/customer';
import { Observable } from 'rxjs/Observable';
import { CustomerService } from '../services/customer.service';
import { ChangeDetectionStrategy } from '#angular/core/src/change_detection/constants';
import { forEach } from '#angular/router/src/utils/collection';
import { AsyncPipe } from '#angular/common';
import { error } from 'util';
import { parse } from 'path';
import { Subscriber } from 'rxjs/Subscriber';
declare var $: any;
#Component({
selector: 'customer',
templateUrl: 'app/customer/views/customer.component.html',
})
export class CustomerComponent implements OnInit {
constructor(private changeDetectorRef: ChangeDetectorRef, private _custSvc: CustomerService) {
}
ngOnInit() {}
customerSearch: CustomerHeaderAndContactsResponse_Read = new CustomerHeaderAndContactsResponse_Read();
onCustomerSearchClick(): void {
this._custSvc.searchCustomers(this.custSearchReqObj).subscribe(
data => {
this.customerSearch = data;
},
err => console.log(err, 'error has occurred'),
() => console.log(this.customerSearch)
);
console.log(this.customerSearch);
}
And below is my model class -
export class CustomerHeaderAndContactsResponse_Read
{
custHeader:Customer[];
custContact:CustomerContact[];
}
Both Customer and CustomerContact classes contain some properties.
And finally here is my template where I am trying to iterate through the object the table rows simply don't display any data. I have used async (AsyncPipe) also but not helping much.
<tr *ngFor="let custItem of customerSearch.custHeader | async; let rowIndex = index">
<td>
<a (click)="onCustomerItemDetailsClick(custItem.acCustomerName, rowIndex)" class="btn">{{custItem.acCustomerName}}</a>
</td>
<td>{{custItem.acCountryId}}</td>
<td>{{custItem.acAreaId}}</td>
<td>{{custItem.acTel}}</td>
<td>{{custItem.acFax}}</td>
<td>{{custItem.acSalesContact}}</td>
<td>
<a (click)="onCustomerContactItemDeleteClick(rowIndex, 'manage-customer')" class="btn" id="btnIconDelete">
<span class="glyphicon glyphicon-trash"></span>
</a>
</td>
</tr>
Please help as I am not unable to understand what/where I am doing mistake.
Do let me know if more information is required.
Thanks in advance!
nitinthombre1991#gmail.com
EDIT -
Tried with BehaviorSubject approach, but now getting an erro like below -
Observable error
The async pipe is used to bind observables directly to the template. So here's what you can do:
data$: Observable<CustomerHeaderAndContactsResponse_Read>;
search$ = new BehaviourSubject<boolean>(true);
ngOnInit() {
this.data$ = this.search$.switchMap(searchObj => this._custSvc.search...(...));
}
onCustomerSearchClick() {
this.search$.next(true);
}
And the template looks like this
<tr *ngFor="let item of data$ | async>...</tr>
So now every time your search is clicked, it will send a call to the service and the async pipe is taking care of displaying the data in the template