带MongoDB的Angular Full Stack应用程序,无法在首页上绑定/显示数据

时间:2019-07-16 01:44:05

标签: node.js angular mongodb typescript

我一直在阅读有关MEAN Stack的书,其中的任务是创建一个全栈Angular应用程序,该应用程序检索主页上的(咖啡馆)位置和数组。用户可以通过本地存储令牌登录和注销应用程序。通过http://localhost:7777/location/<location-id>的各个位置将显示各个位置以及Google地图(基于纬度/经度坐标),用户评论,开放/关闭时间以及与每个位置实例相关的其他相关信息。我面临的问题是我无法通过带有*ngFor的基本'/'路由(即HomepageComponent)来显示locations数组。注意:与检索位置数组有关的所有相关代码都位于其自己的名为HomeListComponent的组件中,该组件又嵌入HomepageComponent中。

我进入了MongoDb数据库的本地实例,以查询位置列表,以便可以检索每个位置的ID。然后,我在Postman中对(EX)http://localhost:7777/location/5970dc1215504ef93ad88919进行了一个简单的GET请求,以查看是否已针对各个位置正确检索了数据。在成功查看通过Postman返回的数据后,我将上面的相同URL复制/粘贴到了浏览器中,并且确实可以通过/location/路由在浏览器中看到渲染到前端的数据。我的目的是排除可能由于后端路由/架构形成而导致的所有错误/错误。

该问题似乎与如何将Angular前端中的getLocations()函数绑定(通过绑定)到getPosition()方法有关,但是我不能肯定地说(我不是有角的退伍军人)。当我在浏览器中转到http://localhost:7777/并打开开发工具以找到<app-home-list>时,我看到绑定没有返回任何内容:

bindings={
  "ng-reflect-ng-for-of": ""
}

我还试图在HomeListComponent中给app-routing-module分配自己的路由(例如,以便我可以查看/测试数据嵌​​入方式是否存在问题:

// {
  //   path: 'locations',
  //   component: HomeListComponent
  // },

...但是那不能解决问题。

我正在使用Node v11.6.0 + Angular v8。

这是后端的基本路线:

router.get('/', ctrlLocations.homelist);

..以及控制器/辅助功能homelist

const homelist = (req, res) => {
  const path = `/api/locations`;
  const requestOptions = {
   url: `${apiOptions.server}${path}`,
    method: 'GET',
    json: {},
    qs: {
      lng: -116.715256,
      lat:  33.746747,
      maxDistance: 20000
    }

  };
  request(
    requestOptions,
    (err, {statusCode}, body) => {
      let data = [];
      if (statusCode === 200 && body.length) {
        data = body.map( (item) => {
          item.distance = formatDistance(item.distance);
          return item;
        });
      }
      renderHomepage(req, res, data);
    }
  );
};

前端/角度:

location.ts

class OpeningTimes {
  days: string;
  opening: string;
  closing: string;
  closed: boolean;
}

export class Review {
  author: string;
  rating: number;
  reviewText: string;
}

export class Location {
  _id: string;
  name: string;
  distance: number;
  address: string;
  rating: number;
  facilities: string[];
  reviews: Review[];
  coords: number[];
  openingTimes: OpeningTimes[];
}

geolocation.service.ts

 public getPosition(cbSuccess, cbError, cbNoGeo): void {
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(cbSuccess, cbError);
    } else {
      cbNoGeo();
    }
  }

distance.pipe.ts

export class DistancePipe implements PipeTransform {

  transform(distance: number): string {
    const isNumeric = function (n) {
      return !isNaN(parseFloat(n)) && isFinite(n);
    };

    if (distance && isNumeric(distance)) {
      let thisDistance = '0';
      let unit = 'm';
      if (distance > 1000) {
        thisDistance = (distance / 1000).toFixed(1);
        unit = 'km';
      } else {
        thisDistance = Math.floor(distance).toString();
      }
      return thisDistance + unit;
    } else {
      return '?';
    }
  }

}

coffeebuzz-data.service.ts

export class CoffeeBuzzDataService {

  constructor(
    private http: HttpClient,
    @Inject(BROWSER_STORAGE) private storage: Storage) { }


  private apiBaseUrl = 'http://localhost:7777/api';


  public getLocations(lat: number, lng: number): Promise<Location[]> {
    const maxDistance: number = 20000;
    const url: string = `${this.apiBaseUrl}/locations?lng=${lng}&lat=${lat}&maxDistance=${maxDistance}`;
    return this.http
      .get(url)
      .toPromise()
      .then(response => response as Location[])
      .catch(this.handleError);
  }


  public getLocationById(locationId: string): Promise<Location> {
    const url: string = `${this.apiBaseUrl}/locations/${locationId}`;
    return this.http
      .get(url)
      .toPromise()
      .then(response => response as Location)
      .catch(this.handleError);
  }

  public addReviewByLocationId(locationId: string, formData: Review): Promise<Review> {
    const url: string = `${this.apiBaseUrl}/locations/${locationId}/reviews`;
    const httpOptions = {
      headers: new HttpHeaders({
        'Authorization': `Bearer ${this.storage.getItem('CoffeeBuzz-token')}`
      })
    };
    return this.http
      .post(url, formData, httpOptions)
      .toPromise()
      .then(response => response as Review)
      .catch(this.handleError);
  }


  private handleError(error: any): Promise<any> {
    console.error('Something has gone wrong', error);
    return Promise.reject(error.message || error);
  }

  public login(user: User): Promise<AuthResponse> {
    return this.makeAuthApiCall('login', user);
  }

  public register(user: User): Promise<AuthResponse> {
    return this.makeAuthApiCall('register', user);
  }

  private makeAuthApiCall(urlPath: string, user: User): Promise<AuthResponse> {
    const url: string = `${this.apiBaseUrl}/${urlPath}`;
    return this.http
      .post(url, user)
      .toPromise()
      .then(response => response as AuthResponse)
      .catch(this.handleError);
  }

}

home-list.component.ts

export class HomeListComponent implements OnInit {


  constructor(
    private coffeeBuzzDataService: CoffeeBuzzDataService,
    private geoLocationService: GeolocationService
  ) { }

  public locations: Location[] = [];


  public message: string;

  ngOnInit() {
    this.getPosition();
  }

  private getPosition(): void {
    this.message = 'Getting your location...';
    this.geoLocationService.getPosition(
      this.getLocations.bind(this),
      this.showError.bind(this),
      this.noGeo.bind(this));
  }

  private getLocations(position: any): void {
    this.message = 'Searching for nearby places';
    const lat: number = position.coords.latitude;
    const lng: number = position.coords.longitude;
    this.coffeeBuzzDataService
      .getLocations(lat, lng)
        .then(foundLocations => {
          this.message = foundLocations.length > 0 ? '' : 'No locations found';
          this.locations = foundLocations;
        });
  }

  private showError(error: any): void {
    this.message = error.message;
  }

  private noGeo(): void {
    this.message = 'Geolocation not supported by this browser';
  }

}

home-list.component.html

<div class="card" *ngFor="let location of locations">
  <div class="card-block">
    <h4>
      <a routerLink="/location/{{location._id}}">{{location.name}}</a>
      <small>&nbsp;
        <i class="fa{{ location.rating < 1 ? 'r' : 's' }} fa-star"></i>
        <i class="fa{{ location.rating < 2 ? 'r' : 's' }} fa-star"></i>
        <i class="fa{{ location.rating < 3 ? 'r' : 's' }} fa-star"></i>
        <i class="fa{{ location.rating < 4 ? 'r' : 's' }} fa-star"></i>
        <i class="fa{{ location.rating < 5 ? 'r' : 's' }} fa-star"></i>
      </small>
      <span class="badge badge-pill badge-default float-right">{{location.distance | distance }}</span>
    </h4>
    <p class="address">{{location.address}}</p>
    <div class="facilities">
      <span *ngFor="let facility of location.facilities" class="badge badge-warning">{{facility}}</span>
    </div>
  </div>
</div>

..最后...

homepage.component.html

<app-page-header [content]="pageContent.header"></app-page-header>
<div class="row">
  <div class="col-12 col-md-8">
    <div class="error"></div>
    <app-home-list></app-home-list>
  </div>
  <app-sidebar [content]="pageContent.sidebar" class="col-12 col-md-4"></app-sidebar>
</div>

我几乎忘了提到我通过家庭/基本路由在后端获得200的状态代码,而没有这样的错误,再次使我相信我无法返回页面上的数据数组加载是Angular绑定问题:

GET / 200 5.431 ms - 1108

在此先感谢任何可以提供一些建议以解决此问题的人。我(诚然)已经对此卡住了一段时间。

干杯:-)

0 个答案:

没有答案