Order Json object - json

I'm creating a simple movie listing app with Angular 4. I'm making an HTTP GET request to fetch all the movies stored in a json file. They have some fields like "Id", "Title", "Genre", "Duration", etc. When i'm listing all the movies, how can i order them by ID descending, so that the last one appear first?
Here's the code that i am using to get this json data:
On my data service file:
getMovies(){
return this.http.get('assets/data/movies.json')
.map(res => res.json());
}
On my component.ts file:
export class MainComponent implements OnInit {
movies: Movies[];
username:string;
userimg:string;
constructor(private userService:UserService, private dataService:DataService) { }
ngOnInit() {
this.dataService.getMovies().subscribe((movies) =>{
this.movies = movies;
});
}
}
interface Movies {
id:number,
title:string,
year:number,
rating:number,
cover:string,
genre:string,
duration:string,
description:string,
favourite:number
}
On my component.html file:
<div *ngFor="let movie of movies" class="row row-movies">
<a [routerLink]="['/movies', {'id': movie.id}]">
<div class="col-md-9">
<h3> {{movie.title}}</h3>
<h4> {{movie.year}}</h4>
<h4> {{movie.rating}}</h4>
<p>{{movie.description}}</p>
<h5> {{movie.genre}}</h5>
<h5> {{movie.duration}}</h5>
</div>
<div class="col-md-3">
<img src="../assets/img/capas/movies/{{movie.capa}}" class="img-responsive capa-filme" width="350px" />
</div>
</a>
</div>
Can you help me please? I'm still very noob with Angular..

This question has nothing to do with angular. You need to do, after loading the movies, something like this:
this.movies.sort((a,b) => (b.id - a.id));
As a note: this works using any Array in vanilla javascript.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

If you don't need the sort to change, you can do it as you retrieve the data.
this.dataService.getMovies().subscribe((movies) =>{
movies.sort((a, b) => {
return a.id < b.id ? 1 : -1;
});
this.movies = movies;
});
NOTE: I did not syntax check this.

Related

Angular NgFor Path Issue

In my Angular Application I have a simple ngFor loop showing logo images like this:
<div *ngFor="let item of list" class="logo-wrapper">
<div class="customer-logo">
<span
class="my-icon"
aria-label="My icon"
[inlineSVG]="'./assets/image/projects/logo/' + item.logo">
</span>
</div>
</div>
This is working fine!
But: If I try to slice the Array to limit the output as follow:
<div *ngFor="let item of list | slice: 0:10; let i = index" class="logo-wrapper">
<div class="customer-logo">
<span
class="my-icon"
aria-label="My icon"
[inlineSVG]="'./assets/image/projects/logo/' + item.logo">
</span>
</div>
</div>
I get this Error : "Object is of type 'unknown'".
Error output:
I really don't know what I'm doing wrong here. I hope someone can point me in the right direction.
Edit: The problem appears as soon as I add a index to the loop.
I tried to add the index to the object like: item.i.logo but its also unknown.
PS: Here is my .ts-file
#Component({
selector: 'app-logo-section',
templateUrl: './logo-section.component.html',
styleUrls: ['./logo-section.component.scss']
})
export class LogoSectionComponent implements OnInit {
list : any
constructor()
{
this.list = getProjects()
console.log(this.list)
}
ngOnInit(): void
{
}
private services = [{
slug : "s-l-u-g",
name : "name",
work : "work",
company : "company",
website : "https://www.google.com",
preview : "text",
logo : "logo.svg"
}]
getProjects()
{
return services
}
}
You would have to change the type of list to any[] instead of any. Update the declaration as follows in your typescript file.
list : any[];
It seems like the SlicePipe deprecates with the ng-inline-svg package because it uses HttpClientModule and works asynchronously.
if you use Array.slice method instead of the SlicePipe in the *ngFor it works fine.
Please find the Stackblitz example.
<div *ngFor="let item of list.slice(0, 10); let i = index" class="logo-wrapper">
<div class="customer-logo">
<span class="my-icon" aria-label="My icon" [inlineSVG]="item.logo"> </span>
</div>
</div>

Property 'name' does not exist on type 'string' ngFor in Angular

I got this error while trying to display an array of objects
Error: src/app/components/timeline/timeline.component.html:9:29 - error TS2339: Property 'name' does not exist on type 'string'.
<h4>{{publication.user.name}}</h4>
~~~~
src/app/components/timeline/timeline.component.ts:10:15
10 templateUrl: './timeline.component.html',
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Error occurs in the template of component TimelineComponent.
in my timeline.component.html I have this:
<div id="publications">
<div *ngFor = "let publication of publications" class="item-publication">
<div class="panel panel-default">
<div class="panel-body">
<h4>{{publication.user.name}}</h4>
</div>
</div>
</div>
</div>
and this is the getPublications function that I have
getPublications(page){
this._publicationService.getPublications(this.token, page).subscribe(
response => {
console.log(response);
if(response.publications){
this.total = response.total_items;
this.pages = response.pages;
this.publications = response.publications;
if(page > this.pages){
this._router.navigate(['/home']);
}
}else{
this.status= 'error';
}
},
error =>{
var errorMessage = <any>error;
console.log(errorMessage);
if(errorMessage != null){
this.status = 'error';
}
}
);
}
If I make a console.log(response) it shows me the values of the array and the properties are correct (name,surname,email, text etc)
In the HTML code, when I do the loop for the publication's text <h4>{{publication.text}}</h4> it works and even if I use <h4>{{publication.user}}</h4> it shows a list of Objects.
I'm taking an online course and basically copying what the teacher does line by line but IDK why when I try to display name and surname properties, it shows the error that I told you
Thank you for your help.
I found the solution and is related to TS type system so basically I have a model object called publication.ts which includes:
export class Publication{
constructor(
public _id:string,
public text: String,
public file: String,
public created_at: String,
public user: String
){}
}
And the issue was related to the type for the property user so by changing its type to public user: any it worked and now it shows the required fields. Sorry for posting this without a deep search before ask for help. Newbie mistakes
Thanks for the help
You are subscribing to the data so there is a small delay in getting the data. Wrap the tag with a *ngIf to wait for the data to be available.
<div *ngIf="publications" id="publications">
<div *ngFor = "let publication of publications" class="item-publication">
<div class="panel panel-default">
<div class="panel-body">
<h4 *ngIf="publication && publication.user && publication.user.name">{{publication.user.name}}</h4>
</div>
</div>
</div>
</div>

how to display data with *ngFor

i trying to display data with *ngFor, but for some reason this doesn't display any data, and any error.
I already tried alot of samples that i found in internet, none of those worked so i decide to ask here.
here is what i have:
ts file:
public querySuccess: any[];
this.userService.getMentions().subscribe(
(returnAPI) => {
this.querySuccess = returnAPI.data;
});
my html:
<div *ngIf="returnAPI">
<div *ngFor="let key of querySuccess">
<div>{{querySuccess.firstName}}</div>
</div>
</div>
<div *ngIf="!returnAPI">
<div>0 results found!</div>
</div>
the getMentions().subscribe() return this Json:
{
total: 3,
data:[
{userId: 0, firstName: "test", lastName: "xzy"},
{userId: 0, firstName: "john", lastName: "yeet"},
{userId: 0, firstName: "jamal", lastName: "abc"}]
}
You don't need that if condition to loop that ngFor.If its to show that no data error message use querySuccess because returnAPI does not seems to defined anywhere.
<div *ngIf="querySuccess">
<div *ngFor="let key of querySuccess">
<div>{{key.firstName}}</div>//key is single istance queryselector is full array.
</div>
</div>
<div *ngIf="!querySuccess">
<div>0 results found!</div>
</div>
you can try like this
<div *ngIf="returnAPI">
<div *ngFor="let key of querySuccess">
<div>{{key.firstName}}</div> <!-- key instead of querySuccess -->
</div>
</div>
Hi i would firstly recommend you put your code in a function like
ngOnInit() {
this.getAllQueries();
}
getAllQueries() {
this.userService.getMentions().subscribe(
(returnAPI) => {
this.querySuccess = returnAPI.data;
return this.querySuccess;
});
}
make sure you call this in the ngOninit function or your constructor

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.

Is there a method to display data from api where the id key is taken from another key?

JSON Data:
"abcd":[
{
"id":"1",
"cityId":"2",
},
{
"id":"2",
"cityId":"3",
}
],
"city":[
{
"id":"2",
"cityName":"california"
},
{
"id":"3",
"cityName":"vicecity"
}
]
Angular:
<div *ngFor="let clg of abcd$">
<p>
{{clg.cityId}}
<!-- Here i need to print the cityname from city by using the cityId we have got from abcd -->
</p>
</div>
app.component.ts:
ngOnInit() {
this.data.getColleges().subscribe(
data => this.abcd$ = data
)
}
fetching data from "abcd" is perfectly working....and no problem in fetching the datas from "city" too. But is it possible to fetch the cityName from "city" by using the cityId key from the "abcd" section.
You can use a method to get city by ID:
app.component.ts:
getCityByID = (cityID) => {
return this.city$.find(item => item.id === cityID);
}
Template:
<div *ngFor="let clg of abcd$">
<p>
{{ clg.cityId }}
{{ getCityByID(clg.cityId).cityName }}
</p>
</div>
Update
As far as I understand, you are fetching colleges and cities with 2 separate observables. Because of this, when you are trying to get city by ID, it may (or may not) throw an error if second observable has not been resolved yet. So, you need to combine/join these two streams together. I prefer combineLatest to do this but forkJoin will work as well.
In app.component.ts:
import { combineLatest } from 'rxjs';
......
ngOnInit() {
combineLatest(
this.data.getColleges(),
this.data.getCity()
).subscribe(([colleges, cities]) => {
this.abcd$ = colleges;
this.city$ = cities;
});
}
This way, you make sure that both abcd$ and city$ are inited. Hope this helps.
For further reading:
combineLatest: https://www.learnrxjs.io/operators/combination/combinelatest.html
forkJoin: https://www.learnrxjs.io/operators/combination/forkjoin.html