Search code examples
node.jsangularhttpget

Angular and Node.js: Get Call parse Data into object


I am new at Angular and I am trying to create a dashboard for plants. So I want to display data from a MySQL database to my Angular app. To pass the plantdata to Angular I use node.js. I have already managed to present a list of my plants. Now I want to display the details for each plant. But the data isn't displayed, because the object plant is undefined. If I try to call directly my node.js server via browser, it works and displays the data as JSON.

I found out, that the data is transferred to my app as JSON correctly and I can display it as a JSON string on my website. I thinks there is a problem to parse the received data from the server into the plant object, because I can't get a vaule by using the dot notation like {{plants.id}} at the HTML. When I try this I got an error like this:

ERROR TypeError: Cannot read property 'id' of undefined
    at Object.eval [as updateRenderer] (PlantDetailComponent.html:11)
    at Object.debugUpdateRenderer [as updateRenderer] (core.js:14735)
    at checkAndUpdateView (core.js:13849)
    at callViewAction (core.js:14195)
    at execComponentViewsAction (core.js:14127)
    at checkAndUpdateView (core.js:13850)
    at callViewAction (core.js:14195)
    at execEmbeddedViewsAction (core.js:14153)
    at checkAndUpdateView (core.js:13845)
    at callViewAction (core.js:14195)

ERROR CONTEXT DebugContext_ {view: {…}, nodeIndex: 0, nodeDef: {…}, elDef: {…}, elView: {…}}

The method getPlant is similar to the method getPlants which works and parses the data correctly.

How can I parse the data into the plant object correctly?

Here is my Angular code:

plant.service:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { catchError, map, tap } from 'rxjs/operators';
import { of } from 'rxjs/observable/of';
import { Plant } from './plant';

@Injectable()
export class PlantService {
  private plantsUrl = 'api/plants';

  constructor(private http: HttpClient) { }

  getPlants(): Observable<Plant[]> {
    return this.http.get<Plant[]>(this.plantsUrl)
      .pipe(
        catchError(this.handleError('getPlants', []))
      );
  }

  getPlant(id: number): Observable<Plant> {
    const url = `${this.plantsUrl}/${id}`;
    return this.http.get<Plant>(url).pipe(
      catchError(this.handleError<Plant>(`getPlant id=${id}`))
    );
  }

  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {
      console.error(error);
      return of(result as T);
    };
  }
}

plant-detail.component:

import { Component, OnInit, Input } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Location } from '@angular/common';

import { Plant } from '../plant';
import { PlantService } from '../plant.service';

@Component({
  selector: 'app-plant-detail',
  templateUrl: './plant-detail.component.html',
  styleUrls: ['./plant-detail.component.css']
})
export class PlantDetailComponent implements OnInit {
  plant: Plant;

  constructor(private route: ActivatedRoute,
    private plantService: PlantService,
    private location: Location
  ) {}

  ngOnInit(): void {
    this.getPlant();

  }

  getPlant(): void {
    const id = +this.route.snapshot.paramMap.get('id');
    this.plantService.getPlant(id)
      .subscribe(plant => this.plant = plant);
  }

  goBack(): void {
    this.location.back();
  }

}

The component and the service are registered in the app.module. I also registered the HttClientModule.

my Node Server:

var express = require("express");
var mysql = require('mysql');
var connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'root',
  database: 'plant_care',
});
var app = express();

app.get("/api/plants", function(req, res) {
  connection.query('SELECT * FROM plant', function(err, rows, fields) {
    if (!err)
      res.send(rows);
    else
      console.log('Error while performing Query.');
  });
});

app.get("/api/plants/:id", function(req, res) {
  const requestedID = req.params.id;
  connection.query('SELECT * FROM plant WHERE ID = ' + requestedID, function(err, rows, fields) {
    if (!err)
      res.send(rows);
    else
      console.log('Error while performing Query.');
  });
});

app.listen(3000, function() {
  console.log("Running...");
});

Solution

  • I solved it.

    My server has sent the data from the MySQL database as an array.

    But my function in plant.service did not expect an array. So there were two ways for me to solve the problem. Either I change the service function that it expects an array, or I change the server that it no longer sends a single record in form of an array.

    I decided to change the server function:

    app.get("/api/plants/:id", function(req, res) {
      const requestedID = req.params.id;
      connection.query('SELECT * FROM plant WHERE ID = ' + requestedID, function(err, rows, fields) {
        if (!err)
          res.send(rows[0]);
        else
          console.log('Error while performing Query:\n' + err);
      });
    });