I am trying to fetch data from API https://sportsbook.draftkings.com/api/odds/v1/leagues/3/offers/gamelines.json
and store them in table in my Angular Application. Initial 15 rows are displayed on my page, not all the rows. And I cannot fetch line data which is nested inside outcome object.
Here is my HTML code
<div class="row">
<mat-toolbar color="primary">
<span>Welcome!</span>
</mat-toolbar>
<div class="container">
<br>
<h2>Information</h2>
<span class="right">API endpoint</span>
<table class="table table-hover">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>HomeTeamName</th>
<th>AwayTeamName</th>
<th>Start Date</th>
<th>Offers</th>
<th>Line</th>
<!--<th>Image</th>-->
</tr>
</thead>
<tbody>
<ng-container *ngFor="let data of data.events">
<tr>
<td>{{data.id}}</td>
<td>{{data.name }}</td>
<td>{{data.homeTeamName }}</td>
<td>{{data.awayTeamName}}</td>
<td>{{data.startDate }}</td>
<td>{{data.offers[1].label }}</td>
<td>{{data.offers.outcomes[2].line }}
<!--<td><img class="image-width" src="{{contact.image}}" alt="{{contact.name}}}"></td>-->
</tr>
</ng-container>
</tbody>
</table>
</div>
</div>
Here is my typescript code
import { Component, OnInit } from '#angular/core';
import { Http, Response } from '#angular/http';
import 'rxjs/add/operator/map';
import { MatTableDataSource, MatSort } from '#angular/material';
import { DataSource } from '#angular/cdk/table';
#Component({
selector: 'app-draftking',
templateUrl: './draftking.component.html',
styleUrls: ['./draftking.component.css']
})
export class DraftkingComponent implements OnInit {
private apiUrl = 'https://sportsbook.draftkings.com/api/odds/v1/leagues/3/offers/gamelines.json';
displayedColumns = ['id','name', 'homeTeamName','awayTeamName','offers','line'];
data: any = {};
dataSource = this.data;
constructor(private http: Http) {
this.getLeague1();
this.getData1();
}
getData1(){
return this.http.get(this.apiUrl)
.map((res: Response) => res.json())
}
getLeague1() {
this.getData1().subscribe(data => {
console.log(data);
this.data = data
})
}
ngOnInit() {
}
}
Typically you setup your actual server call in a service (called model because it models your data). Here is one of mine as an example.
service.ts
#Injectable()
export class ApiService {
constructor(private http: HttpClient) { }
public get<T>(path: string, routerParams?: Params): Observable<T> {
let queryParams: Params = {};
if (routerParams) {
queryParams = this.setParameter(routerParams);
}
return this.http.get<T>(this.path(path), { params: queryParams });
}
public put<T>(path: string, body: Object = {}): Observable<any> {
return this.http.put(this.path(path), body);
}
public post<T>(path: string, body: Object = {}): Observable<any> {
return this.http.post(this.path(path), body);
}
public delete<T>(path: string): Observable<any> {
return this.http.delete(this.path(path));
}
...
In my components (sometimes other services) I will call an API method and expect results in the form of an Observable. So in your case I'd use my service like this:
component
constructor(private apiService: ApiService) { }
ngOnInit() {
this.apiService('https://pathtoserver').subscribe(data => {
if (data.id) {
this.setCurrentUser();
}
});
}
Hey remember to NOT call getData1(); more than once or you'll have 2 "hot" subscriptions. Use .pipe(take(1)).sub... in order to end subscriptions once they give you something.
Related
I'm new to programming and new advise please here is my code
employees component
import { DataService } from './../../service/data.service';
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-employees',
templateUrl: './employees.component.html',
styleUrls: ['./employees.component.css'
]})
export class EmployeesComponent implements OnInit {
employees: any
constructor(private dataservice: DataService) { }
ngOnInit() {
}
getEmployeesData() {
this.dataservice.getData().subscribe((res: any) => {
this.employees = res;
});
}
}
data.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class DataService {
getData: any;
constructor(private httpClient: HttpClient) {
this.httpClient.get('http://127.0.0.1:8000/api/employees')
};
}
HTML
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Surname</th>
<th scope="col">Email</th>
<th scope="col">Salary</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let emp of employees">
<th scope="row">{{emp.id}}</th>
<td>{{emp.name}}</td>
<td>{{emp.surname}}</td>
<td>{{emp.email}}</td>
<td>{{emp.salary}}</td>
</tr>
</tbody>
I see a couple of things, that cause the Data not to show up.
data.service.ts:
Your fetching the Data in the Constructor but you do ignore the return Value of your call. I suggest you do the call in a separate function that will be called if the data is needed.
constructor(private httpClient: HttpClient) {}
loadAllEmployees(): Observable<any> {
return this.httpClient.get('http://127.0.0.1:8000/api/employees');
}
Employees Component:
It seems, that you do not call the getEmployeesData function. Therefore your employees never get any Data.
employees: any
constructor(private dataservice: DataService) { }
ngOnInit() {
this.getEmployeesData();
}
getEmployeesData() {
this.dataservice.loadAllEmployees().subscribe((res: any) => {
this.employees = res;
});
}
With this setup, your data should load and be displayed.
Besides that, I would suggest you define the Type of the Employee and do not work with any. It does make it easier to read and understand your code. You are also less likely to get any Errors regarding types.
The documentation on ngb-pagination in https://ng-bootstrap.github.io/#/components/pagination/overview causes the page to not load after adding this
<ngb-pagination
[(page)]="page"
[pageSize]="pageSize"
[collectionSize]="items.length"></ngb-pagination>
Here is my HTML file
<div class="body d-flex ">
<table class="table table-hover ">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Age</th>
<th scope="col">Email</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let user of users | slice: (page-1) * pageSize : page * pageSize">
<td>{{user.name}}</td>
<td>{{user.age}}</td>
<td>{{user.email}}</td>
<td>action</td>
</tr>
</tbody>
</table>
<ngb-pagination [(page)]="page" [pageSize]="pageSize" [collectionSize]="users.length"></ngb-pagination>
</div>
Here is the ts file
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { environment } from 'src/environments/environment';
#Component({
selector: 'app-table',
templateUrl: './table.component.html',
styleUrls: ['./table.component.scss'],
})
export class TableComponent implements OnInit {
readonly API_PATH = '/user/all';
users: any[] = [];
page = 1;
pageSize = 5;
constructor(private api: HttpClient) {}
async ngOnInit() {
this.displayAllUsers();
}
private async displayAllUsers() {
var users: any = await this.getUsers();
this.getResult(users);
}
private async getUsers(): Promise<any> {
return await this.api.get(environment.API_URL + this.API_PATH).toPromise();
}
private getResult(result: any) {
if (result.success) {
this.users = this.toArray(result.data);
} else {
console.log(result.data);
}
}
private toArray(result: any): any[] {
var list = [];
for (var items in result) {
list.push(result[items]);
}
return list;
}
}
if I remove ngb-pagination snippet the page seems to load perfectly fine, but adding the snippet will fail to load the page
Add the #angular/localize package to your packages.json:
npm install #angular/localize --save
Add this to your polyfills.ts:
import '#angular/localize/init';
This worked for me, when I was having the same problem after upgrading from Angular 6 to 12 and ng-bootstrap 10.
I am using Angular 8, and am querying an endpoint to get an object. When I call it via Advanced REST Client, I get the following returned JSON:
GET: http://localhost:8090/curso_conductor/
Returns:
{
"dato": [{
"ID_CURSO_CONDUCTOR": 1,
"F_INICIO": "2019-09-19T05:00:00.000+0000",
"F_FIN": "2019-12-20T05:00:00.000+0000",
"ESTADO": "1",
"CARNET_C": "l584f",
"F_CADUCIDAD": "2022-06-20T05:00:00.000+0000",
"F_EMISION": "2017-06-20T05:00:00.000+0000",
"ID_CURSO": 1,
"ID_PERSONA": 3
},
{
"ID_CURSO_CONDUCTOR": 2,
"F_INICIO": "2019-08-20T05:00:00.000+0000",
"F_FIN": "2019-12-20T05:00:00.000+0000",
"ESTADO": "1",
"CARNET_C": "8574h",
"F_CADUCIDAD": "2023-04-05T05:00:00.000+0000",
"F_EMISION": "2017-04-08T05:00:00.000+0000",
"ID_CURSO": 1,
"ID_PERSONA": 5
},
{
"ID_CURSO_CONDUCTOR": 3,
"F_INICIO": "2019-10-09T05:00:00.000+0000",
"F_FIN": "2019-12-10T05:00:00.000+0000",
"ESTADO": "1",
"CARNET_C": "2685f",
"F_CADUCIDAD": "2022-08-10T05:00:00.000+0000",
"F_EMISION": "2017-08-09T05:00:00.000+0000",
"ID_CURSO": 1,
"ID_PERSONA": 6
}
],
}
In Angular 8, I then have a service, where I want to make an http call to to the endpoint that will return the above JSON.
getCursoConductor(): Observable<Curso_Conductor[]>{
return this.http.get<Curso_Conductor[]>(this.curso_conductores).pipe();
}
As you can see the result needs to be put into the Curso_Conductor object.
And my model is this:
export class Curso_Conductor {
dato: Dato[];
}
export class Dato {
ID_CURSO_CONDUCTOR: number;
F_INICIO: string;
F_FIN: string;
ESTADO: string;
CARNET_C: string;
F_CADUCIDAD: string;
F_EMISION: string;
ID_CURSO: number;
ID_PERSONA: number;
}
My question is how do I put the data into the Curso_conductorComponent.html?
This is my component.html:
<table class="table table-hover">
<thead>
<tr>
<th>ID</th>
<th>FECHA INICIO</th>
<th>FECHA FIN</th>
<th>ESTADO</th>
<th>Nro CARNET</th>
<th>FECHA CADUCIDAD</th>
<th>FECHA EMISION</th>
<th>IDCURSO</th>
<th>IDPERSONA</th>
<th colspan="2">OPCION</th>
</tr>
</thead>
<tbody>
<tr *ngIf="curso_conductoresObservable | async as curso_conductores else empty">
<tr *ngFor="let curso_conductor of curso_conductores">
<td>{{curso_conductor.id_curso_conductor}}</td>
<td>{{curso_conductor.f_inicio}}</td>
<td>{{curso_conductor.f_fin}}</td>
<td>{{curso_conductor.estado}}</td>
<td>{{curso_conductor.carnet_c}}</td>
<td>{{curso_conductor.f_caducidad}}</td>
<td>{{curso_conductor.f_emision}}</td>
<td>{{curso_conductor.id_curso}}</td>
<td>{{curso_conductor.id_persona}}</td>
<td><button class="btn btn-warning" (click)="Editar(curso_conductor)">Editar</button></td>
<td><button class="btn btn-danger" (click)="Eliminar(curso_conductor)">Eliminar</button></td>
</tr>
</tbody>
</table>
And my component.ts:
curso_conductores: Curso_Conductor[];
constructor(private service: ServiceService, private router: Router) { }
#Input() nombre = '';
ngOnInit() {
this.service.getCursoConductor()
.subscribe(data => {this.curso_conductores=data });
}
I'm getting this error:
Cannot find a differ supporting object
'[object Object]' of type 'object'. NgFor only supports binding to
Iterables such as Arrays.
There are a few issue with your implementation.
The array that you get from the API is present on the dato property. You ideally you should be creating an interface for that:
export interface ApiResponse {
dato: Curso_Conductor[];
}
export interface Curso_Conductor {
ID_CURSO_CONDUCTOR: number;
F_INICIO: string;
F_FIN: string;
ESTADO: string;
CARNET_C: string;
F_CADUCIDAD: string;
F_EMISION: string;
ID_CURSO: number;
ID_PERSONA: number;
}
You'll then have to update your service to reflect the type of data that you're expecting. I'm also changing the name of the service as ServiceService makes no sense at all:
import { Injectable } from "#angular/core";
import { HttpClient } from "#angular/common/http";
import { Observable } from "rxjs";
import { ApiResponse } from "./models/conductor.model";
#Injectable()
export class DataService {
curso_conductores = "assets/data.json";
constructor(private http: HttpClient) {}
getCursoConductor(): Observable<ApiResponse> {
return this.http.get<ApiResponse>(this.curso_conductores);
}
}
You're subscribeing to the Observable in your Component and you're also using an async pipe. Which automatically does the unwrapping for you. So just stick to using the async pipe in the template. That's also what's the recommended way:
import { Component } from "#angular/core";
import { Curso_Conductor, ApiResponse } from "./models/conductors.model";
import { DataService } from "./data.service";
import { Observable } from "rxjs";
import { map } from "rxjs/operators";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
curso_conductores$: Observable<Array<Curso_Conductor>>;
constructor(private service: DataService) {}
ngOnInit() {
this.curso_conductores$ = this.service.getCursoConductor()
.pipe(
map((apiResponse: ApiResponse) => apiResponse.dato)
);
}
}
Finally, the Object fields are all in upper case but you're using them as lower case in the template. That needs to be fixed as well:
<table class="table table-hover" border="1">
<thead>
<tr>
<th>ID</th>
<th>FECHA INICIO</th>
<th>FECHA FIN</th>
<th>ESTADO</th>
<th>Nro CARNET</th>
<th>FECHA CADUCIDAD</th>
<th>FECHA EMISION</th>
<th>IDCURSO</th>
<th>IDPERSONA</th>
<th colspan="2">OPCION</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let curso_conductor of (curso_conductores$ | async) as curso_conductores">
<td>{{curso_conductor.ID_CURSO_CONDUCTOR}}</td>
<td>{{curso_conductor.F_INICIO}}</td>
<td>{{curso_conductor.F_FIN}}</td>
<td>{{curso_conductor.ESTADO}}</td>
<td>{{curso_conductor.CARNET_C}}</td>
<td>{{curso_conductor.F_CADUCIDAD}}</td>
<td>{{curso_conductor.F_EMISION}}</td>
<td>{{curso_conductor.ID_CURSO}}</td>
<td>{{curso_conductor.ID_PERSONA}}</td>
<td><button class="btn btn-warning" (click)="Editar(curso_conductor)">Editar</button></td>
<td><button class="btn btn-danger" (click)="Eliminar(curso_conductor)">Eliminar</button></td>
</tr>
</tbody>
</table>
Hope this clears this up for you.
Here's a Working Sample StackBlitz for your ref.
Are you sure the return type is Curso_Conductor[]? It seems like Curso_Conductor.
Try this,
getCursoConductor(): Observable<Curso_Conductor>{
return this.http.get<Curso_Conductor>(this.curso_conductores).pipe();
}
...
curso_conductore: Curso_Conductor;
constructor(private service: ServiceService, private router: Router) { }
#Input() nombre = '';
ngOnInit() {
this.service.getCursoConductor().subscribe(data => {this.curso_conductore=data });
}
and in html
...
<tr *ngFor="let d of curso_conductore.dato.dato">
<td>{{d.id_curso_conductor}}</td>
<td>{{d.f_inicio}}</td>
...
I have a component named modal. In this model ts file, Im making a http request to get json data from node js. After retrieving Im just displaying it in a table format. My table structre is like below.
modalId modalName subModal AddSubmodal
111 modal1 add
112 modal2 add
The problem here is after clicking the add button, one pop up box will come(Another component) asking us to enter sub model name. There we should display the modal name for which we have to enter sub model details.
So After clicking the add button, I need to pass the modalId to fetch the model details. So here I need to pass the modalID dynamically to the addmodel(second) component. Can anybody tell me how to do this?
My modal.component.ts:
#Component({
selector: 'app-modal',
templateUrl: './modal.component.html',
styleUrls: ['./modal.component.css']
})
export class ModalComponent extends Lifecycle {
public d: any;
constructor(
private $modal: $ModalManagerService,
private http: HttpClient,
) {
super();
}
_initialize(): void {
this.http.get('/getModel',{responseType:"json"}).subscribe(
response => {
this.data = response;
var sample=JSON.stringify(response);
});
}
addSubmodal(modalId){
let obj = this.$modal.show(AddSubModalComponent)
.subscribe(r => {
obj.unsubscribe();
});
};
My modal html:
<table class="table table-bordered" >
<thead>
<tr>
<th>modal ID</th>
<th>modal Name</th>
<th>SubModal</th>
<th>AddSubmodal</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let i of d">
<td>{{ i.Record.modalId }}</td>
<td>{{ i.Record.modalName }}</td>
<td></td>
<td>
<img src="./../Add_Icon.svg" (click)="addSubmodal(i.Record.modalId);">
</td>
</tr>
</tbody>
</table>
As I'm new to angular, Im just browsing angular answers in stackoverflow & doing it. Please tell me how to achieve this in my second component html file?
Use Input & Output Decorators
Basic concept ---> DEMO
app.component.html:
<app-component1 (elm)="catch1Data($event)">
</app-component1>
<app-component2 [elm]="datatocomp2" *ngIf="datatocomp2"></app-component2>
parent component : {{datatocomp2 | json}}
app.component.ts:
datatocomp2: any;
catch1Data(data) {
console.log(data)
this.datatocomp2 = data;
}
component1.ts:
#Output () elm : EventEmitter<any> = new EventEmitter<any>();
objectData: any;
constructor() { }
ngOnInit() {
let objectData = {
comp: 'component 1',
data: 'anything'
}
this.objectData = objectData;
this.elm.emit(objectData)
}
component2.ts:
#Input() elm: any;
constructor() { }
ngOnInit() {
console.log(this.elm);
}
Use a shared service to share data between components, event emitter method isn't the best way for components in routing
Simple example , create a datashare service
//DataShare Service
import { ReplaySubject } from 'rxjs/Rx';
export class DatashareService {
private dataObs$ = new ReplaySubject<any>(1);
getData() {
return this.dataObs$.asObservable();
}
updateData(data) {
this.dataObs$.next(data);
}
constructor() { }
}
In the component where you fetch data,
import { DatashareService } from '../datashare.service';
update the value of the observable
this.dataService.updateData(this.modal_id);
Subscribe to the observable from the sub components
import { Component, OnInit,OnDestroy,NgZone } from '#angular/core';
import { DatashareService } from '../datashare.service';
import { Subscription } from 'rxjs/Subscription';
In the constructor,
constructor(private dataService: DatashareService
,private zone:NgZone){}
Now, access data on init,
ngOnInit() {
this.subscription.add(this.dataService.getData().subscribe(data => {
this.zone.run(()=>{
console.log(data);
this.modal_selected=data;
})
}))
}
Don't forget to unsubscribe on destroy
ngOnDestroy() {
// unsubscribe to ensure no memory leaks
this.subscription.unsubscribe();
}
I trying to render JSON data,
i do as follows...
#Component({
selector:'free-ip',
templateUrl:'./freeip.component.html'
})
export class FreeIpComponent implements OnInit{
getData:string[];
constructor(private http: FreeIpService){}
getFreeIp(){
this.http.getData()
.subscribe(
data => this.getData
);
}
ngOnInit(){
this.getFreeIp();
}
}
My JSON format...
[{"name":"1(К2)","ipange":"85.143.77.64/26","count":14},
{"name":"1(К2)","ipange":"109.123.184.128/26","count":31},
{"name":" 7","ipange":"109.123.188.128/25","count":60}]
Please help me, how to render data to html?
Thank you.
There is a simpler way render in HTML using the built-in json pipe:
<pre>{{getData | json}}</pre>
Try this:-
freeIpService.ts file:-
import { Injectable } from '#angular/core';
import { Http, URLSearchParams} from '#angular/http';
export class FreeIpService {
constructor(private http: Http) { }
getFreeIp(){
this.http.get('src/assets/data/freeId.json').map(response => response.json()
}
}
FreeIpComponent.ts file:-
import { Component, OnInit } from '#angular/core';
import { FreeIpService } from './freeIpService';
export class FreeIpComponent implements OnInit{
getData:any;
constructor(private FreeIpService: FreeIpService){}
ngOnInit(){
this.FreeIpService.getFreeIp().subscribe(response => { this.getData = response}, err => console.log(err), ()=> console.log(this.getData));
}
Create service file and paste the service.ts code and create a component and paste component.ts code. In assets folder create data folder and in data folder create json file freeId.json file and paste json code in this file.
<tr *ngFor="let item of getData">
<td>{{item.name}}</td>
<td>{{item.ipange}}</td>
<td>{{item.count}}></td>
this is that i wanted)
thank all for your help
You should serialize or deserialize your data when it is responsed
The first, this your http service
get(uri: string) {
return this._http.get("your uri", { headers: "your headers"}).map(this.extractData);
}
private extractData(response: Response) {
let data = response.json();
return data || {}
}
The second, this is function implement in component
getAll() {
this._httpProviderService.get("/api/product_category/GET/categories")
.subscribe(result => {
this.productCategories = result;
});
}
And the last, this is html
<tr *ngFor="let item of productCategories;let rowIndex=index">
<td class="a-center ">
<input type="checkbox" class="" name="table_records">
</td>
<td class="">{{rowIndex+1}}</td>
<td class="">{{item.ID}}</td>
<td class="">{{item.Name}}</td>
<td class="">{{item.Description}}</td>
<td class="">{{item.Status}}</td>
</tr>