How to access all the data in the API call - html

getNames(): Observable<bookmodel[]> {
const endpoints = 'https://api.nytimes.com/svc/books/v3/lists/current/hardcover-fiction.json?api-key=xxxxxxxx';
return this.http.get(endpoints).pipe(
map(this.extractData));
}
<h1 class="uk-flex uk-flex-center">Top Books{{bestsellers_date}}</h1>
<hr class="uk-divider-icon">
<div class="uk-child-width-1-5#s uk-grid-match" uk-grid>
<div *ngFor="let name of names; let i = index">
<div class="uk-card uk-card-hover uk-card-body">
<h3 class="uk-card-title">{{name.title}}</h3>
<img style="height:250px;" src="{{name.book_image}}"><br/><br/>
<span>Summary: {{name.description || ' NA' |characters:150}}</span><br />
<hr class="uk-divider-icon">
<span>Author {{name.author}}</span>
<br/>
<br/>Best Sellers Rank {{name.rank}}
<br />
<span>Weeks on List {{name.weeks_on_list}}</span>
<div class="uk-card-footer">
<span><a class="uk-button uk-button-primary" href="{{name.amazon_product_url}}">Buy On Amazon</a></span>
</div>
</div>
</div>
</div>
Okay so the code above makes a call to the api and the api returns an object with nested arrays in order to get the infomation I want Ive put defined the data as data.results.books but theres data that I want to access in the data.results Ive tryed just taking the .books part out but the the NGFOR doesn't work with objects is there a way to store or even get the data in data.results and how would I store it

service.ts
getNames(): Observable<bookmodel[]> {
const endpoints = 'https://api.nytimes.com/svc/books/v3/lists/current/hardcover-fiction.json?api-key=7W3E72BGAxGLOHlX9Oe2GQSOtCtRJXAt';
return this.http.get<bookmodel[]>(endpoints);
}
component.ts
this.service.getNames().subscribe(names => this.names = names);
HTML
<div *ngFor="let name of names; let i = index">
......
</div>
If you are not subscribing it use async pipe in html
<div *ngFor="let name of names | async; let i = index">
......
</div>

Try updating the *ngFor with an async pipe. You need to use async pipe because httpClient always returns Observable.
<div *ngFor="let name of names | async; let i = index"></div>
Also update the getNames and remove the .pipe from there
getNames(): Observable<bookmodel[]> {
const endpoints = 'https://api.nytimes.com/svc/books/v3/lists/current/hardcover-fiction.json?api-key=7W3E72BGAxGLOHlX9Oe2GQSOtCtRJXAt';
return this.http.get<bookmodel[]>(endpoints);
}

Related

Variable in html ,angular

I am working on an app in angular and in an html file i have something like this
<div *ngFor="let var of list">
<div>
{{newVar.name}}
<div>
</div>
My problem is that i dont know how to declare newVar properly in the div because i want newVar to be a result returned from a function in the component that takes the first var as parameter
so i basically want something like
newVar=func(var)
before using the name attribute and i dont know how to do this
I could do func(var).name but i dont only display the name so i dont want to call the function multiple times
So your workaround is something like , streaming list in html and passing var to typescript function func(var) storing result in newVar. From there you want to display name value in UI . Is my understanding is correct , my suggestion is
ts
newVar = [];
///
func() {
list.forEach(element=>{
newVar.push(element);
});
}
html
<div *ngFor="let var of newVar">
<div>
{{var.name}}
<div>
</div>
Currently there aren't any direct solution for this. One workaround is to use *ngFor as a hack (and the cost is performance)
<div *ngFor="let _var of list">
<div *ngFor="let newVar of [func(_var)]">
{{newVar.name}}
</div>
</div>
you has severals options:
<div *ngFor="let var of list">
{{func(var).name}}
</div>
Use an auxiliar array
//in your .ts
auxArray:any[]=[];
this.auxArray=this.list.map(x=>this.func(x))
//and iterate over auxArray
<div *ngFor="let var of auxArray">
{{var.name}}
</div>
//or iterate over list and use "index"
<div *ngFor="let var of list;let i=index">
{{var}} = {{auxArray[i].name}}
</div>
If your list is an array of object you can also
//in your .ts
this.list.forEach(x=>{
data:this.func(x)
}
//and iterate over list but use data.name
<div *ngFor="let var of list">
{{var.data.name}}
</div>
The first option has a poor efficency because Angular execute the function several times -each time check the application, you can see if use a console.log(var) in your function
You can pass variables to newvar function like this.
<div *ngFor="let var of list">
<div> {{newVar(var)}} <div>
</div>
i have found a solution,basically you can do something like
<div *ngIf="func(var) as newVar">
{{newVar.name}}
</div>

Ionic React too slow to render JSON file containing 100+ objects in IonCard component

I am creating a mobile app with Ionic React. I render multiple IonCards with dynamic data coming from a local JSON file. Actually, I'm mapping through the JSON file. Everything is fine. But it takes a couple of seconds to render all the cards. I want to minimize the loading time. Please help me with how do I optimize the render time and overall performance of the application. The code is below:
//imports...
import data from "../db/data.json";
const Products: React.FC = (filterText) => {
const [searchText, setSearchText] = useState("");
const categories = vocabTopics
//filtering CATEGORIES
.filter((topic) => {return topic.title.toLowerCase().indexOf(searchText.toLowerCase()) >= 0;})
.map((topic) => {
return (
<IonCol size="12" key={topic.id}>
<IonCard mode="md" routerLink={topic.route} className="except-home-screen-card no-margin no-radius-card">
<div className="flex">
<div className="card-img">
<img src={topic.thumbnail}></img>
</div>
<div className="flex-justify-space-b-w">
<div>
<IonCardSubtitle className="except-home-screen-card-subtitle">{topic.subtitle}</IonCardSubtitle>
<IonCardTitle className="except-home-screen-card-title">{topic.title}</IonCardTitle>
</div>
<div>
<IonIcon icon={chevronForwardOutline} className="card-right-icon"/>
</div>
</div>
</div>
</IonCard>
</IonCol>
);
});
return (
<IonPage>
<IonHeader className="ion-no-border">
<IonToolbar className="top-header">
<IonButtons slot="start" className="top-header-icons color-primary">
<IonBackButton defaultHref="home" /></IonButtons>
<div className="top-title-container">
<IonTitle className="ion-text-center v-center">Products</IonTitle>
</div>
</IonToolbar>
</IonHeader>
<IonContent fullscreen className="bg-style">
<div className="center padding-y">
<h1 className="lg-text ion-no-margin equal-padding">Products Categories</h>
<p className="ion-text-center ion-no-margin subtitle">70+ CATEGORIES</p>
</div>
<IonGrid className="my-grid ion-no-padding">
<IonSearchbar spellcheck={true} autocorrect="on" className="searchbar" value={searchText} mode="ios" onIonChange={(e) => setSearchText(e.detail.value!)}></IonSearchbar>
<IonRow className="center-padding">
<div className="card-container fluid">
{categories}
</div>
</IonRow>
</IonGrid>
</IonContent>
</IonPage>
);
};
export default Products;
I suppose 100 Cards are not visible at the same time in a single "view", so the only solution is the "infinite scrolling" and Display/Create them only when them should became visible. (example: https://forum.ionicframework.com/t/infinite-scrolling-of-data-from-the-api/172933)

when using a GET method data is coming in console not in HTML

I have written my get method inside ngOnInIt(). When I am printing data in console it is visible, but when printing in HTML using interpolation, it is returning [ object object]
{{filteredCourses}} ==> [object object]
and when i am using {{course.category|json}} so here i am getting all values of array ["course" : "database" , "category" : "database" , "length" : "2hr" ] thats how the value is coming
html :-
<div class="courses" fxLayout="row wrap" fxLayoutAlign="center" [#animateStagger]="{value:'50'}">
<div class="course" *ngFor="let course of filteredCourses" fxFlex="100" fxFlex.gt-xs="50"
fxFlex.gt-sm="33" [ngClass]="course.category" [#animate]="{value:'*',params:{y:'100%'}}">
<div class="course-content" fxLayout="column" fxFlex="1 1 auto">
<div class="header" fxLayout="row" fxLayoutAlign="center center"
[ngClass]="course.category + '-bg'">
<div class="category" fxFlex>
{{course.category|json}}
</div>
</div>
</div>
Code:
filteredCourses: any[];
this.product_name = getProduct()['name'];
console.log(this.product_name);
this.token = getToken();
this.httpHeaders = new HttpHeaders({ "Authorization": "Bearer " + this.token });
this._httpClient.get('http://127.0.0.1:8000/api/products/info/'+this.product_name+'/',{headers: this.httpHeaders})
.subscribe(
data => {
this.product = data;
this.courses = data['cources'];
this.filteredCourses = this.courses;
console.log(this.filteredCourses);
},
error => {
console.log(error);
}
);
try using JSON.stringify(yourObject) or maybe in certain cases you can use Object.keys().
You need to use loop if its an array of object or you might want to print the properties of object individually.
But if you want to see the object filteredCourses in template, use json pipe.
{{filteredCourses | json}}
In case you need help to print values using *ngFor or properties, do let us know.
I suppose filteredCourses collection contains an array of objects. So you need to iterate through filteredCourses using ngFor directive to render data in the HTML template.
Like:
<ul>
<li ngFor="let item of filteredCourses">{{item.courseName}}</li>
</ul>

Fetching individual JSON data on reactJS

When I parse A JSON from my server to my react front end it works fine perfectly but when I add a parameter to display an individual item I get an error. How do I display individual JSON data on react JS. I get the JSON data from my rest server. My code looks like the following.
In order to get the JSON I use the following method.
state = {
isLoading: true,
groups: [],
};
async componentDidMount() {
const response = await fetch('/product/all/1');
const body = await response.json();
this.setState({ groups: body, isLoading: false });
}
This is how I call the array
{this.state.groups.map(group => <div className="col-sm-12 col-md-6 col-lg-4 p-b-50">
{/* Block2 */}
<div className="block2">
<div className="block2-img wrap-pic-w of-hidden pos-relative block2-labelnew">
<img src={group.thumbnail} />
<div className="block2-overlay trans-0-4">
<a href="#" className="block2-btn-addwishlist hov-pointer trans-0-4">
<i className="icon-wishlist icon_heart_alt" aria-hidden="true" />
<i className="icon-wishlist icon_heart dis-none" aria-hidden="true" />
</a>
<button key={group.id} onClick={() => this.add(group.productid, group.name)} className="flex-c-m size1 bg4 bo-rad-23 hov1 s-text1 trans-0-4">Add to Cart</button>
</div>
</div>
<div className="block2-txt p-t-20">
<a href={`/productdetails/` + group.productid}>{group.name}</a>
</div>
</div>
</div>)}
I get an error saying "TypeError: this.state.groups.map is not a function"
My Spring backend to call all items and individual items look as the following
#GetMapping("/product")
public List<Product> index(){
return productRepository.findAll( );
}
#GetMapping("/product/all/{id}")
public Product show(#PathVariable String id){
int productId = Integer.parseInt(id);
return productRepository.findOne(productId);
}
P.S both api's seem working fine when tested on postman and fetching ("api/products") too works fine
this.state.groups.map is not a function . This means React expects this.state.groups to be an array. If you are returning only one item then do it like it this:
this.setState({ groups: [body], isLoading: false });
this way, body will be the first and only item in an array.

Angularjs convert string to object inside ng-repeat

i've got a string saved in my db
{"first_name":"Alex","last_name":"Hoffman"}
I'm loading it as part of object into scope and then go through it with ng-repeat. The other values in scope are just strings
{"id":"38","fullname":"{\"first_name\":\"Alex\",\"last_name\":\"Hoffman\"}","email":"alex#mail","photo":"img.png"}
But I want to use ng-repeat inside ng-repeat to get first and last name separate
<div ng-repeat="customer in customers">
<div class="user-info" ng-repeat="name in customer.fullname">
{{ name.first_name }} {{ name.last_name }}
</div>
</div>
And I get nothing. I think, the problem ist, that full name value is a string. Is it possible to convert it to object?
First off... I have no idea why that portion would be stored as a string... but I'm here to save you.
When you first get the data (I'm assuming via $http.get request)... before you store it to $scope.customers... let's do this:
$http.get("Whereever/You/Get/Data.php").success(function(response){
//This is where you will run your for loop
for (var i = 0, len = response.length; i < len; i++){
response[i].fullname = JSON.parse(response[i].fullname)
//This will convert the strings into objects before Ng-Repeat Runs
//Now we will set customers = to response
$scope.customers = response
}
})
Now NG-Repeat was designed to loop through arrays and not objects so your nested NG-Repeat is not necessary... your html should look like this:
<div ng-repeat="customer in customers">
<div class="user-info">
{{ customer.fullname.first_name }} {{ customer.fullname.last_name }}
</div>
This should fix your issue :)
You'd have to convert the string value to an object (why it's a string, no idea)
.fullname = JSON.parse(data.fullname); //replace data.fullname with actual object
Then use the object ngRepeat syntax ((k, v) in obj):
<div class="user-info" ng-repeat="(nameType, name) in customer.fullname">
{{nameType}} : {{name}}
</div>
My advise is to use a filter like:
<div class="user-info"... ng-bind="customer | customerName">...
The filter would look like:
angular.module('myModule').filter('customerName', [function () {
'use strict';
return function (customer) {
// JSON.parse, compute name, foreach strings and return the final string
};
}
]);
I had same problem, but i solve this stuff through custom filter...
JSON :
.........
"FARE_CLASS": "[{\"TYPE\":\"Economy\",\"CL\":\"S \"},{\"TYPE\":\"Economy\",\"CL\":\"X \"}]",
.........
UI:
<div class="col-sm-4" ng-repeat="cls in f.FARE_CLASS | s2o">
<label>
<input type="radio" ng-click="selectedClass(cls.CL)" name="group-class" value={{cls.CL}}/><div>{{cls.CL}}</div>
</label>
</div>
CUSTOM FILTER::
app.filter("s2o",function () {
return function (cls) {
var j = JSON.parse(cls);
//console.log(j);
return j;
}
});