我一直在开发一个应用程序,该应用程序从MongoDB传递用户事件帖子并以HTML呈现它们:
Event-post.ts
ngOnInit() {
this.postsService.getPosts();
this.postSub = this.postsService.getPostUpDateListener()
.subscribe((posts: Post[]) => {
this.posts = posts;
Event-post.html
<mat-expansion-panel *ngFor="let post of posts">
<!-- Display event posts -->
这很好。但是,最近我决定创建一个附加功能,该功能允许用户根据与他们所在位置的接近程度来过滤事件。用户输入邮政编码,然后从下拉菜单中选择距离。数据经过一系列计算;将邮政编码转换为经纬度,计算点与点之间的距离,最后根据所需距离进行过滤。
receivePost($event) {
this.postFilter = $event;
/****************** Convert Event Posts to LAT LNG **********************************/
this.eventPostcode = [];
console.log('Incoming POSTS: ', this.posts);
for (let i = 0; i < this.posts.length; i++) {
this.geoCodingService.geocodeAddress(this.posts[i].postcode)
.subscribe(
location => {
this.lat = location.lat;
this.lng = location.lng;
const e: EventPostcode = {lat: this.lat, lng: this.lng};
this.eventPostcode.push(e);
/* console.log('TEST: ', this.eventPostcode);*/
}
);
}
/****************** Convert reference post to LAT LNG **************************/
this.myPostcode = [];
this.geoCodingService.geocodeAddress(this.postFilter)
.subscribe(
location => {
this.lat = location.lat;
this.lng = location.lng;
const m: MyPostcode = {lat: this.lat, lng: this.lng};
this.myPostcode.push(m);
this.calcDist();
}
);
}
/******************** Calculate distance between each point **********************/
calcDist() {
const posts = [];
const haversineCalculator = require('haversine-calculator');
for ( let i = 0; i < this.eventPostcode.length; i++) {
const start = {
latitude: this.myPostcode[0].lat,
longitude: this.myPostcode[0].lng
};
const end = {
latitude: this.eventPostcode[i].lat,
longitude: this.eventPostcode[i].lng
};
/***** Filter according to distance (Options: 15, 25, 50 miles) */
if (haversineCalculator( start, end, {unit: 'mile'}) < this.distFilter) {
console.log(haversineCalculator( start, end, {unit: 'mile'}));
posts.push(this.posts[i]);
}
}
console.log('Filtered posts: ', posts);
this.posts = posts;
}
当我尝试更新视图中的新列表时出现问题。如果我注释掉this.posts = posts,有效地禁用HTML呈现,并通过console.log('Filtered posts',posts)检查过滤后的数组,一切正常。帖子完全按照我的要求进行过滤。但是,一旦尝试在视图中呈现数据,一切就会崩溃。
尽管控制台中没有显示任何明显的错误,但是当我激活事件处理程序时,该过程的执行速度极慢,大约需要8秒钟才能最终更新视图。
除此问题外,当我检查从数据库传递的帖子(this.posts)进入事件处理程序时,每次按Enter时它们都会减少。因此,如果我从数据库中的6个事件开始并筛选到3个,则下次触发该事件时,只有3个事件可用。
我非常感谢任何人对这个问题所提供的任何指导。 感谢您的宝贵时间。
答案 0 :(得分:0)
除此问题外,当我检查从数据库传递的帖子(this.posts)进入事件处理程序时,每次按Enter时它们都会减少。因此,如果我从数据库中的6个事件开始并筛选到3个,则下次触发该事件时,只有3个事件可用。
致电calcDist()
时,您会使用经过过滤的新帖子来更新this.post
。调用receivePost()
时,只需使用this.post
即可,而无需对其进行重置。因此,每次调用calcDist()
时,都可能会缩短this.post
的长度,而且似乎永远不会将this.post
重置为原始长度。这可以解释为什么每次您过滤事件时,事件的数量似乎会永久减少。
我也不确定为什么要将lat
和lng
保存到类变量中,因为这些类变量将仅包含最后给定的值。即您正在遍历数组并每次都覆盖this.lat
和this.lng
。由于可观察对象是异步执行的,因此您甚至无法保证它们的回调函数将被调用的顺序。您真的不知道this.lat
和this.lng
的最终值是什么。>
最后,对api进行观察的可观察对象是异步函数。您似乎依赖它们来同步执行,因为您在this.calcDist()
订阅回调的末尾调用了this.geoCodingService.geocodeAddress(this.postFilter)
。但是,据您所知,该回调可能会在任何this.geoCodingService.geocodeAddress(this.posts[i].postcode)
回调之前执行。意味着this.eventPosts
被调用时,this.calcDist()
的长度可以为0(即使有 are 事件发布)。
一种可能的解决方案,将您的可观察变量转换为承诺并使用await
以确保执行顺序是您想要的。
示例:
async receivePost($event) {
this.postFilter = $event;
// as I mentioned, you need some way of resetting posts to get rid of old filtering
this.posts = originalPosts;
/****************** Convert Event Posts to LAT LNG **********************************/
this.eventPostcode = [];
const geocodedEventLocations = await Promise.all(
this.posts.map(post =>
this.geoCodingService.geocodeAddress(post.postcode).toPromise()
)
);
geocodedEventLocations.forEach(location => {
this.eventPostcode.push({
lat: location.lat,
lng: location.lng,
})
});
/****************** Convert reference post to LAT LNG **************************/
this.myPostcode = undefined; // not sure why you were setting this to an array before...
const postFilterLocation =
await this.geoCodingService.geocodeAddress(this.postFilter).toPromise();
this.myPostcode = {
lat: postFilterLocation.lat,
lng: postFilterLocation.lng,
};
this.calcDist();
}
/******************** Calculate distance between each point **********************/
calcDist() {
const posts = [];
const haversineCalculator = require('haversine-calculator');
this.eventPostcode.forEach((eventPostcode, index) => {
const start = {
latitude: this.myPostcode.lat,
longitude: this.myPostcode.lng
};
const end = {
latitude: eventPostcode.lat,
longitude: eventPostcode.lng
};
/***** Filter according to distance (Options: 15, 25, 50 miles) */
if (haversineCalculator( start, end, {unit: 'mile'}) < this.distFilter) {
posts.push(this.posts[index]);
}
})
this.posts = posts;
}
我还没有测试过这个例子,可能还有其他问题,但是希望您能理解。
最后,我认为您进行设置是有原因的
const haversineCalculator = require('haversine-calculator');
在calcDist()
方法调用内,而不是简单地使用
import * as haversineCalculator from 'haversine-calculator';
位于文件顶部(甚至是const haversineCalculator = require('haversine-calculator');
位于文件顶部)。