我从API调用获取数据。我有很多对很多的关系-我会和人们一起看电影。一部电影被很多人看,一个人可以看许多电影。 因此,在Angular Frontend中,单击某个人时,应该可以更详细地查看该人的视图,包括其观看的电影列表。
当我运行此代码(person-detail.component.ts)时:
public selectedperson: any = []
/*Array that contains data from the selected person*/
public movie: any = []
/*Array that contains all the movie-person connections (movie-name and person_id)*/
public selectedmovie: any = []
/*array that should contain all the movies the selectedperson has watched*/
/*some code*/
getMovies(){
const url ='http://localhost:4000/api/people-movies';
this.http.get(url).subscribe(movie => {
this.movie = movie;
this.selectedmovie=this.movie.find(item=>
{
for (var i = 0; i < this.movie.arrayLength; i++) {
if(item['person_id']===this.selectedperson.person_id)
{
return true;
}
return false;
}
});
console.log(this.selectedmovie, this.selectedperson.person_id);
return this.selectedmovie;
});
}
它不起作用-但没有此循环(并且如果我离开If语句):
for (var i = 0; i < this.movie.arrayLength; i++) {
}
它只会返回此人的一部电影-因此,一旦找到电影,它就会停止播放。但是由于我要列出所有电影,因此需要循环播放。
那么循环出现了什么问题?
编辑: 选定人员中的样本数据(已填写): 被选人:
[{"person_id"=34, "name"="john"}]
电影(通过具有上述URL的API调用获取此数据):
[{"person_id"=33, "movie"="Titanic"}{"person_id"=33, "movie"="Star Wars"}{"person_id"=34, "movie"="Titanic"}{"person_id"=34, "movie"="Star Wars"}{"person_id"=34, "movie"="Indiana Jones"}{"person_id"=35, "movie"="Titanic"}]
想要最终结果(对于ID为34的人)
Titanic
Star Wars
Indiana Jones
答案 0 :(得分:1)
您可以尝试这样。
this.selectedmovie = this.selectedmovie.filter(item => {
for (var i = 0; i < this.movie.arrayLength; i++) {
if (item['person_id'] === this.selectedperson.person_id) {
return true;
}
}
return false;
});
注意:Javascript array.find方法返回提供的数组中满足提供的测试功能的第一个元素的值。
答案 1 :(得分:1)
您的代码有些错误,但是我将从我认为适合您的解决方案开始:
getMovies(){
const url ='http://localhost:4000/api/people-movies';
this.http.get(url).subscribe(movie => {
this.movie = movie;
this.selectedmovie=this.movie.filter(item=> item['person_id'] === this.selectedperson.person_id );
console.log(this.selectedmovie, this.selectedperson.person_id);
return this.selectedmovie.map(movie.movie);
});
}
现在,您的代码有什么问题:
您尝试通过激活自身上的selectedmovie
来填充空数组find
,但它是空的...而是使用{{1}中的电影填充它}数组。
您正在使用movie
,对文档(here)的简单了解可以清楚地表明,它仅返回满足测试功能的第一个元素。取而代之的是使用find
,它有点相同,但会遍历整个数组并返回所有满足测试的对象。
您可以在不使用filter
的情况下进行for循环-这实际上是不需要循环的明显信号。
当整个检查是单个布尔表达式时,无需返回“ true”或“ false”,它将内联返回。
单方面来说,您的变量名称确实很难理解。例如,包含电影的数组最好称为“电影”,而当您使用数组函数对其进行迭代时,每个元素都可以称为“电影”。两者使用相同的名称确实令人困惑。还要尝试使用驼峰表示法(selectedMovie),这样会使名称更清晰。
**注意:我的解决方案只会按照您想要的方式从“ getMovies”返回数组,因为i
链接在返回值上。如果您希望仅使用电影名称作为字符串而不是整个movie-perosn_id对象来填充.map
,只需将selectedmovie
链接到.map
,就像这样:
filter
希望对您有所帮助:)
答案 2 :(得分:1)
您可以这样获得所需的结果:
const movie = [
{"person_id":33, "movie":"Titanic"},
{"person_id":33, "movie":"Star Wars"},
{"person_id":34, "movie":"Titanic"},
{"person_id":34, "movie":"Star Wars"},
{"person_id":34, "movie":"Indiana Jones"},
{"person_id":35, "movie":"Titanic"}
];
let selectedperson = [{"person_id":34, "name":"john"}];
let moviesByPerson = movie.filter(f=>
selectedperson.some(s=> f['person_id'] == s['person_id']));
console.log(`moviesByPerson: `, moviesByPerson);
在您的代码中:
getMovies(){
const url ='http://localhost:4000/api/people-movies';
this.http.get(url).subscribe(movie => {
this.movie = movie;
this.selectedmovie = movie.filter(f=>
selectedperson.some(s=> f['person_id'] == s['person_id']));
console.log(this.selectedmovie, this.selectedperson.person_id);
return this.selectedmovie;
});
}
此外,请尝试将HTTP调用移入服务,因为这是区分关注点的好习惯。 As Angular docs says:
组件不应该直接获取或保存数据,它们当然 不应故意提供虚假数据。他们应该专注于呈现 数据并委托对服务的数据访问。
答案 3 :(得分:1)
某些问题,如前所述,您正在使用find
,它将仅返回第一个匹配项(如果存在)。您正在寻找filter
来过滤与ID匹配的电影。另外,您正在尝试从subscribe
返回,这是行不通的。我也会改变你的做法。 请勿使用any
,它违反了 Type 脚本的目的。因此,键入数据(例如使用接口)将为您提供帮助,因为编译器会告诉您是否执行了与模型不符的操作,这使调试变得更加容易!
我还将所有http请求移至服务,该组件仅订阅该http请求的结果。所以总的来说,我建议以下几点:
interface Movie {
person_id: number;
movie: string;
}
interface Person {
person_id: number;
name: string;
}
服务:
import { map } from "rxjs/operators";
// ...
getFilteredMovies(id: number) {
const url ='http://localhost:4000/api/people-movies';
return this.http.get<Movie[]>(url).pipe(
map((movies: Movie[]) => {
return movies.filter((m: Movie) => m.person_id === id)
})
)
}
组件:
movies = <Movie[]>[];
selectedPerson = <Person>{ person_id: 34, name: "john" };
constructor(private myService: MyService) {}
ngOnInit() {
this.myService
.getFilteredMovies(this.selectedPerson.person_id)
.subscribe((data: Movie[]) => {
this.movies = data;
});
}
因此,我们已经在服务中处理了过滤,并且组件仅订阅。 如果,您在其他不希望执行过滤的地方调用了此函数,然后在组件中执行过滤。
STACKBLITZ demo 和上面的代码。
答案 4 :(得分:0)
我终于解决了它-感谢erveryone的帮助,尤其是@Gibor! 这是遇到类似问题的人的代码: 但是,请注意,该代码绝非完美,必须以多种方式加以改进(例如,使用循环查找所有电影)。我只是将其发布在这里,希望对遇到类似问题的人有所帮助... component.ts:
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ActivatedRoute} from '@angular/router';
@Component({
selector: 'app-people-detail',
templateUrl: './people-detail.component.html',
styleUrls: ['./people-detail.component.css']
})
export class PeopleDetailComponent implements OnInit {
public data: any = []
public selectedperson: any = []
public movies: any = []
public moviesByPerson: any = []
constructor(
public http: HttpClient,
public route: ActivatedRoute) { }
getPeople()
{
const person_id = this.route.snapshot.paramMap.get('person_id')
const people_url ='http://localhost:4000/api/people'
const movies_url ='http://localhost:4000/api/person-movie'
this.http.get(people_url).subscribe
(data =>
{
this.data = data;
this.selectedperson=this.data.find
(item=>
{
if(item['person_id']===person_id)
{
return true;
}
return false;
}
)
this.http.get(movies_url).subscribe
(movies =>
{
this.movies = movies;
this.moviesByPerson=this.movies.filter(item => item.person_pk === this.selectedperson.person_pk)
}
)
console.log(this.selectedperson, this.moviesByPerson)
return this.selectedperson, this.moviesByPerson
}
)
}
ngOnInit()
{
this.getPeople()
}
}
component.html:
<div><span>ID: </span>{{selectedperson.person_id}}</div>
<h1>{{selectedperson.name}}</h1>
<p>{{selectedperson.age}}</p>
<p></p>
<table>
<thead>
<tr>
<th>Movies</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{moviesByPerson[0].movie}}</td>
</tr>
<tr>
<td>{{moviesByPerson[1].movie}}</td>
</tr>
<tr>
<td>{{moviesByPerson[2].movie}}</td>
</tr>
</tbody>
</table>