error TS2740 on Angular when trying to load .json - json

I am a novice in Angular/Typescript and I am trying to build a dynamic page with the champion_info.json in order to display all the data in a list. I tried to upload the data from my json file but I have this error and I don't know what to do about it. I watched every possible youtube video about this subject but I still can't find an answer.
How can I simply load my data from the .json file and use it in order to display it in a list ?
This is my hero.component.ts :
import { Component, OnInit } from '#angular/core';
import * as Heroes from "src/hero_json/champion_info.json";
interface heroes1 {
title: String;
id: Number;
name: String;
key:String;
}
#Component({
selector: 'app-hero',
templateUrl: './hero.component.html',
styleUrls: ['./hero.component.css']
})
export class HeroComponent implements OnInit {
liste !: heroes1 = Heroes;
constructor() {
}
ngOnInit(): void {
}
}
This is the error
And this is where you can find the champion_info.json file: https://www.kaggle.com/datasnaek/league-of-legends?select=champion_info.json

Probably the problem is you need to add
declare module "*.json" {
const value: any;
export default value;
}
in a file in the app folder as
json-typings.d.ts
Anyways here is the repo I create to answer your question with basic and complete way to build this app you can clone a try to u
repor basic app

First, as you have indicated above you need to get .data from the JSON object, in your component class:
heroes = json_data.data;
In your template use the angular keyvalue pipe to parse and display data where you have a list of objects rather than an array.
<div *ngFor="let hero of heroes | keyvalue">
{{ hero.value.title }}
{{ hero.value.name }}
// etc
</div>

Related

ngFor Property 'id' does not exist on type 'Object'

Im trying to learn angular and Im following a code tutorial and as far as I can tell my code matches the instructors but it's not working.
I have the following code and it fails to compile saying the objects dont exist. what am i missing?
import { ThrowStmt } from '#angular/compiler';
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-product',
templateUrl: './product.component.html',
styleUrls: ['./product.component.css']
})
export class ProductComponent implements OnInit {
products:Object[];
constructor() {
this.products = [
{
id: "1",
name:"Mac Book Pro"
},
{
id: "2",
name:"iPhone"
}
];
}
public getProducts(){
return this.products;
}
ngOnInit(): void {
}
}
Product Details:
<div *ngFor="let product of products">
<h1>{{product.name}}</h1>
<h1>{{product.id}}</h1>
</div>
it prints out [[object Object]] twice if i remove the .name and .id, but as it stands i get the following errors.
4 <h1>{{product.name}}{{product.id}}</h1>
~~~~
src/app/product/product.component.ts:6:16
6 templateUrl: './product.component.html',
~~~~~~~~~~~~~~~~~~~~~~~~~~
Error occurs in the template of component ProductComponent.
Error: src/app/product/product.component.html:4:35 - error TS2339: Property 'id' does not exist on type 'Object'.
4 <h1>{{product.name}}{{product.id}}</h1>
~~
SOLVED
I have solved the issue by changing from Object[] to any[].
products:any[];
this solved the issue.
Solution 1
You have to specify products type as the array with strongly typed class/interface instead of Object[];
product.model.ts
export interface Product {
id: string;
name: string;
}
product.component.ts
import { Product } from '../models/product.model';
products: Product[];
Sample Solution 1 on StackBlitz
Solution 2
Alternative, change the text interpolation as below if you prefer products as Object[] type.
<div *ngFor="let product of products">
<h1>{{product["name"]}}</h1>
<h1>{{product["id"]}}</h1>
</div>
Sample Solution 2 on StackBlitz
Try using ? operator, like this:
<div *ngFor="let product of products">
<h1>{{product?.name}}</h1>
<h1>{{product?.id}}</h1>
</div>
Your current code will break if any product is missing name or id property.
The issue was using the type Object[] Swapping to any[] solved the issue.
Change products:Object[]; to products:any[];
I.e the type should be any instead of Object. this is a general angular bug. Hope they resolve it.

Best way to store/display data in angular

So I have a FAQ page which I have developed in angular and I have hardcoded all the data in a html file .I just wanted to know is there a better way of displaying the data like storing it in a XML/JSON/TXT file and read the file and display it or store the XML/JSON/TXT file in angular and read form it**(if storing it where to store it)**.
.Browsed for a few articles didn't find anything helpful ,any guidance will be appreciated. I am new to angular so just looking for some advice ,thanks in advance.
If your data is static I recommend storing it in a JSON file inside your angular application under the assets folder.
You can then use Angular HttpClient to retrieve the content of the file.
In this example, the file is called 'data.json' and is stored under the 'assets' folder:
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'my-component',
templateUrl: './my-component.html',
styleUrls: ['./my-component.css']
})
export class MyComponent implements OnInit {
constructor(private http: HttpClient) { }
ngOnInit() {
this.http.get('/assets/data.json').subscribe().then(data => console.log(data));
}
}
You can find more information here.

How to get data from array in JSON - Angular 7+

I'm completely beginning in Angular and API. I'm trying to resolve some problem. My task is simple i guess. I have to get currency exchange rates data from NBP Web API. JSON file looks like:
I've found solution how to get some data from JSON, but i still have problem with array. The json file was converted to typescript and the result was :
So my Code look's like that:
Exchange.model.ts
export interface Exchange {
table: string;
no: string;
effectiveDate: string;
rates: Rate[];
}
export interface Rate {
currency: string;
code: string;
mid: number;
}
app.component.ts
import { Component, OnInit } from '#angular/core';
import { Exchange, Rate } from './exchange.model';
import { DataService } from './data.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
exchanges$: Exchange;
rates$: Rate;
constructor(private dataService: DataService) {}
ngOnInit() {
return this.dataService.getExchanges().subscribe(data => this.exchanges$ = data)
}
ngOnInit2() {
return this.dataService.getRates().subscribe(data => this.rates$ = data)
}
}
and app.component.html
<div *ngFor='let exchanges of exchanges$'>
<h2">{{exchanges.table}} <br> {{exchanges.no}} <br> {{exchanges.effectiveDate}}</h2">
{{exchanges.rates}}
</div>
The browser display the data like that:
The result is almost good. But the data from "rates" in JSON doesn't work.
"rates":[
{
"currency":"bat (Tajlandia)",
"code":"THB",
"mid":0.1261
},"
How to solve a problem? How to get data from array in JSON into typescript? What input into array in Exchange.module.ts?
I know that, a question is long, but I wanted to display necessary code and images.
You already have an Array as you see it displays a list of objects on your page. Since Rate is also an object you need to display its properties to see something meaningful.
If you want to display all the rates you can do another *ngFor for the rates like you do for exchanges.
For Example:
<div *ngFor="let exchanges of exchanges$">
<h2>{{exchanges.table}} <br> {{exchanges.no}} <br> {{exchanges.effectiveDate}}</h2>
<div *ngFor="let rate of exchanges.rates">{{rate.code}} {{rate.mid}} {{rate.currency}}</div>
</div>
You did not explain very well what kind of output you want to get. If you want some additional processing it is better you move it inside the component code.

Angular - What's the best way to include html in multiple components?

I need to put a loading in multiple components of my project. So instead of putting the same HTML over and over again across the components, I need to know what's the best way to not repeat code, but I don't know if this is correct thing to do. I have created a component called loading-graphic, which I bind it in every HTML file of the respective components. I read about ngTemplateOutlet and ngContent, but to be honest it doesn't make sense in my head to use it for this case (and I don't get it too... I'm a beginner on it). So, on what should I bet? Thanks.
Base on your question, I think creating Reusable Components with NgTemplateOutlet would be the best solution to avoid repeating HTML in different component Templates. It allows you to pass parameters base on your host component and makes your Angular app easier to test and develop since it sllows easily modified reusable component for various use cases without having to modify individual components itself.
Since you are a begginer I am going to Illustrate simple way of using NgTemplateOutlet, however dive deep later on Templates and Stamps.
Imaging you have a reusable Search component where you want to hide a check box base on the parent component. Your Template will look like below.
we pass data from the parent component to the child/Search component using #Input and property binding, so we define which checkboxes to hide base on Parent component.
here is the code sample for Search Component
search.component.ts
======================
import { Component, OnInit, Output, EventEmitter, Input } from '#angular/core';
#Component({
selector: 'app-search',
templateUrl: './app-search.component.html',
styleUrls: ['./app-search.component.css']
})
export class AppSearchComponent implements OnInit {
accountName: string = '';
#Output() accountSearchChange = new EventEmitter<string>(); //1. Event Binding to pass data from Child to Parent Component ->Int
#Input() searchMode: 'account' | 'holder' | 'distribution' = 'account'; //Use NgTemplateOutlet for reusable componenet
constructor() { }
ngOnInit() {
}
//2. Event Binding to pass data from Child to Parent Component ->Invoke Emit
doSearchFilter(searchText: string) {
console.log('Search Child: doSearchFilter -> ' + searchText);
this.accountSearchChange.emit(searchText);
}
clearFilters() {
console.log('Account Search: Clear Filter is called');
this.accountName = '';
}
}
search.component.html
=====================
<ng-container [ngSwitch]="searchMode">
<div class="input-full-width" *ngSwitchCase="'account'">
<mat-checkbox class="example-container check-full-width">Show active and pending only</mat-checkbox>
</div>
<div class="input-full-width" *ngSwitchCase="'holder'">
<mat-checkbox class="example-container check-full-width">View only holders with missing requirements</mat-checkbox>
</div>
<div class="input-full-width" *ngSwitchCase="'holder'">
<mat-checkbox class="example-container check-full-width">View only active Holders</mat-checkbox>
</div>
</ng-container>
I am using Search component inside Account component and below is the code sample.
in HTML file i am referring app-search css selector and pass the search Mode defined in ts.
import { Component, OnInit, ViewChild, AfterViewInit } from '#angular/core';
import { MatSort, MatTableDataSource, MatPaginator } from '#angular/material';
import { Router } from "#angular/router";
import { Observable } from 'rxjs';
import { AccountService } from 'src/app/core/services/account.service';
import { Deal } from 'src/app/core/models/deal';
#Component({
selector: 'app-account',
templateUrl: './account.component.html',
styleUrls: ['./account.component.css']
})
export class AccountsComponent implements OnInit, AfterViewInit {
displayedColumns: string[] = ['accountId', 'accountShortName', 'accountType'];
public dealDataSource = new MatTableDataSource<Deal>();
dealsObservable: Observable<Deal[]>;
searchMode = 'distribution';
isLoadingResults = true;
#ViewChild(MatSort) sort: MatSort;
#ViewChild(MatPaginator) paginator: MatPaginator;
constructor(private router: Router, private api: AccountService) { }
......................................................
<app-search (accountSearchChange)='doFilter($event)' [searchMode]="searchMode"></app-search>
Hope this is clear.
i think loading component is not a bad Idee. Use loading component in your app-root component. You can use a loading.service and interceptor to display or hide the component. You will get automatically a Loading Indicator for each API call.
sample: https://medium.com/#zeljkoradic/loader-bar-on-every-http-request-in-angular-6-60d8572a21a9

Access constant in HTML in Ionic 3

My project is in Ionic 3. I have a data provider class for storing constants.
ex
export const CONST1 = 1;
export const CONST2 = 2;
#Injectable()
export class DataProvider {
constructor() {
}
}
In my Display Page, I want to use the constant data. So If I do
import * as Data from './../../providers/data/data';
I can directly access Data.CONST1 in my Display.TS file.
How do access the values in my Display.HTML file? There Data.CONST1 is not working.
One way to do it would be by assigning the Data object to a public property of that component:
import * as Data from './../../providers/data/data';
// ...
#Component({
selector: 'page-display,
templateUrl: 'display.html'
})
export class DisplayPage {
public constants = Data;
// ...
}
And then in the view
<p>{{ constants.CONST1 }}</p>
EDIT:
I want to use it as an input parameter and <ion-input
maxLength="constants.CONST1"></ion-input> does not work.
That's actually because you need to use attribute binding, to let angular know that the expression between "" must be interpreted:
<ion-input [attr.maxLength]="constants.CONST1"></ion-input>