angular2 - response not rendered in html - javascript

I'm learning angularjs2. Here Ihave tried to call API and got response. But the response not render in homepage.component.html. I'm not sure what Im wrong. and I want use this response in another page also without calling API again. I dont know how to that. Please help with this.
homepage.component.ts
import { Component, OnInit,Injectable } from '#angular/core';
import {Http, Response} from '#angular/http';
import 'rxjs/add/operator/toPromise';
import {Observable} from 'rxjs/Rx';
import { Router } from '#angular/router';
import { CountriesService } from './countries.services';
import { Countries } from './countries';
#Component({
moduleId: module.id,
selector: 'my-homepage',
templateUrl: 'homepage.component.html',
styleUrls: [ 'homepage.component.css' ],
providers: [ CountriesService ]
})
export class HomepageComponent implements OnInit {
errorMessage: string;
public edited = false;
Countries : Countries[];
constructor(private router: Router,private CountriesService: CountriesService) { }
ngOnInit(){
this.CountriesService.getCountries().subscribe(
Countries => {Countries = Countries,console.log(Countries);},
error => this.errorMessage = <any>error);
}
}
homepage.component.html
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 remove_padding images">{{Countries.msg}} Test
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-12 remove_padding" *ngFor="let Cities of Countries">
<img class="img-responsive" src="{{Cities.img}}" alt="{{Cities.city}}">
<div class="topleft">
{{Cities.city}}
<p class="city_para">{{Cities.country}}</p>
<!--<p>23 food places and more!</p>-->
</div>
</div>
</div>
countries.services.ts
import { Injectable } from '#angular/core';
import { Http, Headers,Response} from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
import { Countries } from './countries';
#Injectable()
export class CountriesService {
private CountryListUrl = "APIURL";
private CityByCatUrl = "APIURL";
constructor(private http: Http) {}
getCountries(): Observable<any> {
const headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
headers.append('Access-Control-Allow-Methods', 'GET,PUT,POST,OPTIONS');
headers.append('Access-Control-Allow-Origin', '*');
return this.http.get(this.CountryListUrl,{headers: headers})
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let Countries = res.json();
console.log(Countries);
return Countries || { };
}
private handleError(error: Response) {
return Observable.throw(error.json().error || "500 internal server error");
}
}
countries.ts
export class Countries {
Status: Number;
msg: String;
categorylist:JSON ;
}

You need to see what you are actually receiving:
{
"Status":1,
"categorylist":[
{
// whatever properties you have...
"id":1,
"city":"cityOne"
}
// more...
],
"msg":"List Found!"
}
Countries is not an array that you can iterate, it's an object, with an array inside it, called categoryList. I suppose that is what you want to iterate through.
So when you have subscribed to your object, and notice the subscribe, you need to assign the data to your Object Countries:
.subscribe(data => {
this.Countries= data;
});
And as said, Countries is not an array, but an object, so you should change the initialization from Countries : Countries[]; to Countries:Countries = {}
You can iterate the categoryList that is inside the object:
<div *ngFor="let Cities of Countries.categorylist">
<a>{{Cities.city}}</a>
</div>
Not really knowing what your array contains, you need to adjust the properties accordingly in your own code.
Here's a
DEMO
PS. No need to use a class here, change your Countries to Interface and change categorylist: JSON to....
export interface Countries {
Status: Number;
msg: String;
categorylist: array[];
}

The problem is with your data population. Can you check adding this.Countries while assigning the response.
ngOnInit(){
this.CountriesService.getCountries().subscribe(
Countries => {
Countries = this.Countries,
console.log(Countries);
},
error => this.errorMessage = <any>error);
}

Related

Blank results when iterating through a non-empty array in angular template

EDIT: I made changes in the push method but it still did not work
I am making get request to an api and pushing each of the responses to an array. The array is visible when logged to console. On printing the length of the array in the template length comes out to be 5. But when I try to iterate through it using ngFor no output is being displayed
Service
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import {Quote} from 'src/app/models/quote';
#Injectable({
providedIn: 'root'
})
export class StockpriceService {
url1='https://financialmodelingprep.com/api/v3/quote-short/';
url2='?apikey=efa24b272821b542c459557332c02a1e';
constructor(private http:HttpClient) {
}
//alpha apikey="VETRGM94G70WQGX9";
getQuote(symbol:string) //load data from api
{
return this.http.get<Quote>(this.url1 + symbol + this.url2);
}
}
ts file
import { Component, OnInit } from '#angular/core';
import{Quote} from 'src/app/models/quote';
import{StockpriceService} from 'src/app/services/stockprice.service';
import { timer } from 'rxjs';
#Component({
selector: 'app-stocks',
templateUrl: './stocks.component.html',
styleUrls: ['./stocks.component.css']
})
export class StocksComponent implements OnInit {
stocks: Array<Quote>=[];
symbols=['AAPL', 'GOOG', 'FB', 'AMZN', 'TWTR'];
constructor(private serv:StockpriceService) { }
ngOnInit(): void {
this.symbols.forEach(symbol => {
this.serv.getQuote(symbol).subscribe(
(data:Quote)=>{
console.log(data);
this.stocks.push(
{
symbol:data.symbol,
price:data.price,
volume:data.volume
}
);
}
)
});
console.log('stocks array is')
console.log(this.stocks);
}
}
Template
<div *ngFor="let stock of stocks">
{{stock.symbol}}
{{stock.price}}
</div>
sample api response
[ {
"symbol" : "AAPL",
"price" : 126.81380000,
"volume" : 36245456
} ]
Accordingly I have an interface defined for it as
export interface Quote{
symbol:string;
price:number;
volume:number;
}
This will work fine.
this.serv.getQuote(symbol).subscribe((data: Quote[]) => {
console.log(data);
this.stocks.push(...data);
});

Passing data between components using a service Angular

There are many examples around the web on this subject but none of them helped me. This is the scenario: I've got 2 components and a service. The two components aren't parent/children but are 2 independent components. One of them has a list of names, the other should load a table when one of the names is clicked. This is my home.html with both components
<div class="material-docs-app">
<div class="docs-primary-header">
<h1>Yep!</h1>
</div>
<div fxLayout="row" fxLayout.xs="column" class="component-layout-body">
<app-heroes-sidenav></app-heroes-sidenav>
<app-heroes-table #heroesTable fxFlex="1 2 calc(15em + 20px)" style="width: 100%"></app-heroes-table>
</div>
</div>
Heroes sidenav component:
<div *ngIf="loadingData == true">
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div>
<nav *ngIf="loadingData == false">
<p *ngFor="let item of heroesNames.results let i = index" [attr.data-index]="i">
<button mat-button (click)="getHero(i)">
{{item.name}}
</button>
</p>
</nav>
On click getHero() is called correctly. This is the sidenav component ts:
import { Component, OnInit, Input } from '#angular/core';
import {SwCharactersServiceService} from '../sw-characters-service.service';
import {HeroesTableComponent} from '../heroes-table/heroes-table.component';
#Component({
selector: 'app-heroes-sidenav',
templateUrl: './heroes-sidenav.component.html',
styleUrls: ['./heroes-sidenav.component.css']
})
export class HeroesSidenavComponent implements OnInit {
heroesNames: any;
heroData:any;
loadingData = true;
#Input() heroesTable: HeroesTableComponent;
constructor(private _swService: SwCharactersServiceService) { }
ngOnInit() {
this.getHeroes();
}
getHeroes() {
this._swService.getCharacters().then(result => {
this.loadingData = false;
this.heroesNames = result;
});
}
getHero(index) {
this._swService.getHero(index);
}
}
and this is the service:
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import 'rxjs/add/operator/map'
import {Observable} from 'rxjs/Observable';
#Injectable({
providedIn: 'root'
})
export class SwCharactersServiceService {
param:any;
constructor(private http: HttpClient) { }
getCharacters(): Promise<any[]> {
return this.http.get<any[]>("https://swapi.co/api/people/")
.toPromise()
.then(result => result)
.catch(this.handleError);
}
getHero(index): Observable<any>{
console.log(index);
let headers = new HttpHeaders();
headers.append('Content-Type', 'application/json');
return this.http.get("https://swapi.co/api/people/" + index, {
headers: headers
}).map(res => res );
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error); // for demo purposes only
return Promise.reject(error.message || error);
}
}
I can correctly see the console.log(index) but the request doesn't work. There is no request initiated in chrome console network tab.
This is the component with the table:
import { Component, OnInit, Input, Output, EventEmitter } from '#angular/core';
import { Subscription } from 'rxjs/Subscription';
import {SwCharactersServiceService} from '../sw-characters-service.service';
#Component({
selector: 'app-heroes-table',
templateUrl: './heroes-table.component.html',
styleUrls: ['./heroes-table.component.css']
})
export class HeroesTableComponent implements OnInit {
loadingData = true;
heroData :any;
subscription: Subscription;
constructor(private _swService: SwCharactersServiceService) {
this.subscription = this._swService.getHero(1).subscribe(result => { this.heroData = result; });
console.log(this.heroData);
}
ngOnInit() {
}
ngOnDestroy() {
// unsubscribe to ensure no memory leaks
this.subscription.unsubscribe();
}
}
There are 2 problems now:
1) As you can see I wrote this._swService.getHero(1) without passing a dynamic param. How does it work? How can I pass the correct index?
2) The service doesn't fire and I haven't got any result.
Is there any other way to do that?
Thanks.
you can use BehaviourSubject to pass the index value and send the query request as the list is cliked
in the service
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
public index: BehaviorSubject<number> = new BehaviorSubject<number>(null);
in the sidenav component
getHero(index) {
this._swService.index.next(index);
}
in the hero table component
ngAfterViewInit(){
this._swService.index.subscribe(index=>{
if(index){
this._swService.getHero(index).subscribe(result => { this.heroData = result; });
}
})
}
You missed to subscribe to _swService.getHero(). If not subscribed to a method which returns an Observable, then it wont be invoked.
getHero(index) {
this._swService.getHero(index).subscribe(
(resp) => {
// manipulate your response here
console.log(resp);
},
(err) => {}
);
}

Angular 5 - HTTP Client - converting resp.body to Array

I am trying to get my JSON response from the HttpClient service into an array so that I can loop through using *ngFor in my html. I've tried using "this" to loop through but *ngFor will not accept it. Below is the code for my service.ts component and the main component.ts.
I just need some way to convert an array from "resp.body" into an exportable Array to be used for string interpolation in the html. Any help would be much appreciated!
races.component.ts
import { Component, OnInit } from '#angular/core';
import {Race, RacesService} from './races.service';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'dh-races',
templateUrl: './races.component.html',
providers: [ RacesService ],
styleUrls: ['./races.component.scss']
})
export class RacesComponent {
error: any;
headers: string[];
race: Race;
raceM: any[];
constructor(private racesService: RacesService) {
var raceM = [];
var raceArray = [];
this.racesService.getRaceResponse()
.subscribe(resp => {
raceArray.push(resp.body);
for (let obj of raceArray) {
for (let i in obj) {
raceM.push({
"ID": obj[i].id + ",",
"Date": obj[i].activityStartDate,
"RaceName": obj[i].assetName,
"Website": obj[i].website
})
}
console.log(raceM);
return raceM;
}
});
}
races.service.ts
#Injectable()
export class RacesService {
constructor(private httpClient: HttpClient) { }
getRace() {
return this.httpClient.get(activeApiURL).pipe(
retry(3),
catchError(this.handleError)
);
}
getRaceResponse(): Observable<HttpResponse<Race>> {
return this.httpClient.get<Race>(
activeApiURL, {
observe: 'response'
});
}
To fix the issue, you need to create an interface that matches the data you get from the server, I will call this interface IRace.
Then in the component I will create a variable named races, I will assign the returned value from the server response i.e. resp.body to the races variable.
I'd change the service to look like this:
export interface IRace {
// Your response from server object's properties here like so:
id: Number;
assetName: string;
...
}
export class RacesService {
constructor(private httpClient: HttpClient) { }
getRace() {
return this.httpClient.get(activeApiURL).pipe(
retry(3),
catchError(this.handleError)
);
}
getRaceResponse(): Observable<HttpResponse<Array<Race>>> {
return this.httpClient.get<Array<Race>>(
activeApiURL, {
observe: 'response'
});
}
}
Finally, I'd change the race component to this:
import { Component, OnInit } from '#angular/core';
import { Race, RacesService, IRace } from './races.service';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'dh-races',
templateUrl: './races.component.html',
providers: [ RacesService ],
styleUrls: ['./races.component.scss']
})
export class RacesComponent {
error: any;
headers: string[];
races: IRace[];
constructor(private racesService: RacesService) {
this.racesService.getRaceResponse()
.subscribe(resp => {
this.races = resp.body;
});
}
}
I hope this helps.

How to display data from MONGODB to ANGULAR 5's html

I've been stuck here since yesterday.
I have an API that retrieves data from mongodb (mlab.com)
var helpers = require('../config/helper.js');
var UserModel = require('../model/UserModel.js');
module.exports = function (server){
server.get("/", function (req, res, next) {
UserModel.find({}, function (err, users) {
helpers.success(res, next, users);
});
});
}
This is the UserModel.js
const mongoose = require('mongoose');
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var UserSchema = new Schema({
id: ObjectId,
fname: String,
lname: String,
email_add: String,
champ_type: String
});
var UserModel = mongoose.model('users', UserSchema);
module.exports = UserModel;
My app.js
//packages
const restify = require('restify');
const mongoose = require('mongoose');
const restifyValidator = require('restify-validator');
const corsMiddleWare = require('restify-cors-middleware');
//local
var setupController = require('./controller/setupController.js');
var userController = require('./controller/userController.js');
var config = require('./config/dbConfig.js');
//init packages
const server = restify.createServer();
mongoose.connect(config.getMongoConnection());
setupController(server, restify, restifyValidator, corsMiddleWare);
userController(server);
server.listen(8080, function () {
console.log('%s listening at %s', server.name, server.url);
});
ALL OF THE ABOVE IS WORKING WHEN I TRIED IT ON POSTMAN
SCREENSHOT OF THE POSTMAN
NOW LET'S GO TO MY ANGULAR 5 PROJECT
First, I generate a component(retrieve.component) using the CLI.
Second, I created a service[logging.service.ts], code:
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { Injectable } from '#angular/core';// If you need external data
import { Http, Response, Headers, RequestOptions, URLSearchParams } from '#angular/http';// If you need to call some API from the cloud
import { Request } from "#angular/http";
// Import RxJs required methods
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { LogModel } from '../model/log.model';
#Injectable()
export class LoggingService {
private ROOT_URL = "http://localhost:8080/";
constructor(private http: Http) {}
//getPosts() {
//let params = new HttpParams().set('userId', '1');
//this.posts = this.http.get(this.ROOT_URL /*, { params }*/);
//}
addComments(): Observable<LogModel[]> {
let headers = new Headers({ "Content-Type": "application/json" }); // ... Set content type to JSON
let options = new RequestOptions({ headers: headers }); // Create a request option
return this.http
.get(this.ROOT_URL, options)
.map((response: Response) => response.json())
.catch((error: any) =>Observable.throw(error.json().error || "Server error"));
}
test() {
//console.log("Hello!");
const subject = new Subject();
subject.subscribe({
next: function(value) {
console.log(value);
}
});
subject.next("Hello!");
subject.next("Free!");
}
}
Third, I created a model (log.model.ts), code:
export interface LogModel {
lname: String;
fname: String;
email_add: String;
champ_type: String;
}
Fourth, I configured my component (retrieve.component.ts), code:
import { Component, OnInit } from '#angular/core';
import { Observable } from "rxjs/Observable";
import { LoggingService } from "../service/logging.service";
import { LogModel } from "../model/log.model";
#Component({
selector: "app-retrieve",
templateUrl: "./retrieve.component.html",
styleUrls: ["./retrieve.component.css"]
})
export class RetrieveComponent implements OnInit {
//posts: Observable<any>;
private results: LogModel[];
private model: any;
constructor(private _loggingservice: LoggingService) {}
getAllusers() {
this.model = this._loggingservice.addComments().subscribe(data => {
this.results = data;
//this.results = Array.of(this.results);
}
err => console.error(err),
() => console.log('getBooks completed')
);
console.log(this.model);
}
ngOnInit() {
this._loggingservice.test();
}
}
Fifth, configured my retrieve.component.html, code:
<p>
retrieve works!
</p>
<button (click)="getAllusers()">Get Posts</button>
<div *ngFor="let item of results?.data">
<p>Output: {{ item }}</p>
</div>
Sixth, configured my app.module.ts, code:
// This typescript file is called a module. It is a group of components bundled together.
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import {
NgForm,
FormBuilder,
FormGroup,
Validators,
FormArray,
FormControl,
FormsModule
} from "#angular/forms"; // for you to enable ngModel in HTMLs
//import { HttpClientModule } from '#angular/common/http';
import { HttpModule } from "#angular/http";
import { AppComponent } from './app.component';
// Before you can use a component, you'll need to declare it here
import { ServerComponent } from './server/server.component';
import { ServersComponent } from './servers/servers.component';
import { ProfileComponent } from './iprofile/profile.component';
import { ProfileService } from './iprofile/profile.service';
import { LoggingService } from './service/logging.service';
import { RetrieveComponent } from './retrieve/retrieve.component';
#NgModule({
declarations: [
AppComponent,
// Then here.
ServerComponent,
ServersComponent,
ProfileComponent,
RetrieveComponent
],
imports: [
BrowserModule,
FormsModule, // for you to enable ngModel in HTMLs
HttpModule
],
providers: [ProfileService, LoggingService],
bootstrap: [AppComponent]
})
export class AppModule {}
Lastly, I implement it on the main html (app.component.html), code:
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
<h1>
Welcome to {{ name }}!
</h1>
<img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
</div>
<input type="text" [(ngModel)]="name">
<h3>Facker</h3>
<hr>
<app-servers></app-servers>
<app-profile></app-profile>
<app-retrieve></app-retrieve>
<!--
<h2>Here are some links to help you start: </h2>
<ul>
<li>
<h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
</li>
</ul> -->
Here's the screenshot of the output PS. When I press "get Posts" button it shows "[Object object]"
So, thank you for reading all the stuff. I just want to know what goes wrong? I just want to display to my Angular 5 project what the postman displayed. I'm trying to google simple tutorials but it doesn't work. By the way, restify and corsmiddleware are my default packages, what I mean is you can suggest but I think that won't solve the problem.
So, you have got this piece of code:
getAllusers() {
this.model = this._loggingservice.addComments().subscribe(data => {
this.results = data;
//this.results = Array.of(this.results);
data here is represented as a json, but you want it to be an object. Try to JSON.parse() your data like this:
getAllusers() {
this.model = this._loggingservice.addComments().subscribe(data => {
this.results = JSON.parse(data);
If this isn't working, try to JSON.stringify() your response instead of response.json here:
return this.http
.get(this.ROOT_URL, options)
.map((response: Response) => response.json())
Here I give working example of getting response from API and parsing it into custom object:
public loadPage() {
this.http
.get(environment.API_URL + "search/" + this.query + "/" + pageToLoad.toString())
.map((data) => JSON.stringify(data))
.subscribe((data) => {
const page: Product[] = JSON.parse(data);
this.showedProducts = this.showedProducts.concat(page);
});
}

"Supplied parameters do not match any signature of call target." while using a get to gather information from API

I'm getting this error and i'm new to angular 2 so i'm not 100% sure on how to resolve the issue, i'm connecting to a test API to return a javascript object which includes some dummy data. But my "this.onGet()" function is telling me that the supplied parameter does not match any signature of call target and i can't seem to figure out why.
(Essentially i'm just trying to populate the orderInfo array with the information from the API so i can use it across multiple page)
Any help appreciated :)
App.component.ts
import { Component, OnInit } from '#angular/core';
import { DetailsService } from './details.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [DetailsService]
})
export class AppComponent implements OnInit {
orderInfo = [
{
name: 'Test'
}
];
constructor(private detailsService: DetailsService) {
}
ngOnInit() {
this.onGet();
}
onGet(name: string) {
this.detailsService.getDetails()
.subscribe(
(orderData: any[]) => {
this.orderInfo.push({
name: name
});
console.log(orderData);
}
);
}
}
details.service.ts
import {Injectable} from '#angular/core';
import { Http, Response } from '#angular/http';
import 'rxjs/Rx';
#Injectable()
export class DetailsService {
constructor(private http: Http) {}
getDetails() {
return this.http.get('http://swapi.co/api/people/1/?format=json', '')
.map(
(response: Response) => {
const orderData = response.json();
return orderData;
}
);
}
}
The signature of http get method is
get(url: string, options?: RequestOptionsArgs) : Observable<Response>
You are passing a extra string parameter
getDetails() {
///////////////removed below single quotes
return this.http.get('http://swapi.co/api/people/1/?format=json')
.map(
(response: Response) => {
const orderData = response.json();
return orderData;
}
);
Look into your
ngOnInit() {
this.onGet(); //////////nothing passed
}
where as your method signature is onGet(name:string) you are not passing anything as above
Your OnGet function is expecting a string parameter, which is not supplied while calling from ngOnInit.

Categories