简体   繁体   中英

Angular 5 HTTP response undefined

I am working on a small full stack project with angular and nodejs and express. I have an issue where one of my methods in the dataservice is not returning the data and having debugged it, it states that the return value is undefined.

//Client-Side

Clubs.ts

export interface Clubs {
  id?: number;
  club_name: string;
  specific_category_id?: number;
  club_category_id?: number;
  county_id?: number;
}

app-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { NavbarComponent } from './components/navbar/navbar.component';
import { HomeComponent } from './components/home/home.component';
import { ClubsComponent } from './components/clubs/clubs.component';
import { SearchByCountiesComponent } from './components/search-by-counties/search-by-counties.component';
import { SearchByClubsComponent } from './components/search-by-clubs/search-by-clubs.component';
import { SearchSportsComponent } from './components/search-sports/search-sports.component';
import { SearchClubsComponent } from './components/search-clubs/search-clubs.component';    

const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'club-category/search', component: SearchByClubsComponent },
  { path: 'club-category/search/:county_id', component: SearchByClubsComponent },
  { path: 'counties/search', component: SearchByCountiesComponent },
  { path: ':slug/search', component: SearchSportsComponent },
  { path: ':slug/search/:countyID', component: SearchSportsComponent },
  { path: 'clubs/search', component: SearchClubsComponent },
  { path: 'club/:id', component: ClubsComponent }
]

@NgModule({
  exports: [RouterModule],
  imports: [
    RouterModule.forRoot(routes)
  ],
  declarations: []
})
export class AppRoutingModule { }

search-club-component.ts

import { Component, OnInit } from '@angular/core';
import { Clubs } from '../../models/clubs';
import { DataService } from '../../services/data.service';

@Component({
  selector: 'app-search-clubs',
  templateUrl: './search-clubs.component.html',
  styleUrls: ['./search-clubs.component.scss']
})
export class SearchClubsComponent implements OnInit {
  //Declare Properties
  clubs: Clubs[];

    constructor(
      private dataService: DataService
    ) { }

  ngOnInit() {
    //Get all Clubs
    this.dataService.getClubs().subscribe(clubs => {
      console.log('Response has been received ');
      this.clubs = clubs;            
    });
  }

}

data.service.ts

import { Injectable } from "@angular/core";    
import { Observable } from "rxjs/Observable";    
import { ClubType } from "../models/clubtype";
import { County } from "../models/county";
import { SportCategory } from "../models/SportCategory";
import { Clubs } from "../models/Clubs";    
import { HttpClientModule, HttpClient } from "@angular/common/http";

@Injectable()
export class DataService {
  //Declare properties
  localHost = "http://localhost:3000";

  constructor(private httpClient: HttpClient) {}

  //Get ClubTypes
  getClubTypes(): Observable<ClubType[]> {
    return this.httpClient.get<ClubType[]>(
      this.localHost + "/club-category/search"
    );
  }

  //Get ClubTypes
  getClubTypesByCounty(countyID): Observable<ClubType[]> {
    return this.httpClient.get<ClubType[]>(
      this.localHost + '/club-category/search/'+ countyID
    );
  }

  //Get Counties
  getCounties(): Observable<County[]> {
    return this.httpClient.get<County[]>(this.localHost + "/counties/search");
  }

  //Get Counties
  getSportCategory(slug): Observable<SportCategory[]> {
    return this.httpClient.get<SportCategory[]>(
      this.localHost + '/'+ slug +'/search'
    );
  }

  //Get Specific Category By County
  getSportCategoryByCounty(slug, countyID): Observable<SportCategory[]> {
    return this.httpClient.get<SportCategory[]>(
      this.localHost + '/'+ slug +'/search/' + countyID
    );
  }

  //Get Clubs
  getClubs(): Observable<Clubs[]> {        
    return this.httpClient.get<Clubs[]>(this.localHost + "/clubs/search"); 
  }
}

//Server-Side

app.js

const express = require("express");
const path = require('path');
const mysql = require('mysql');
const connectionPool = require('./config/database');

//Create Connection
const db = mysql.createConnection({
  host:'localhost',
  user: 'someUser',
  password: '******',
  database: 'dataBaseName'
});

db.connect((err) =>{
  if(err){
    console.log(err);
    throw err;
  }
  console.log('MySQL connected...');
});

const app = express();

//JSON Prettify
app.set('json spaces', 40);

// Add headers
app.use(function (req, res, next) {

  // Website you wish to allow to connect
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');

  // Request methods you wish to allow
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

  // Request headers you wish to allow
  res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

  // Set to true if you need the website to include cookies in the requests sent
  // to the API (e.g. in case you use sessions)
  res.setHeader('Access-Control-Allow-Credentials', true);

  // Pass to next layer of middleware
  next();
});  

//Set Routes
const clubcategories = require('./routes/club-categories');
const counties = require('./routes/counties');
const sportcategories = require('./routes/sport-categories');
const clubs = require('./routes/clubs');


//Use Routes
app.use('/club-category', clubcategories);
app.use('/counties', counties);
app.use('/sport', sportcategories);
app.use('/clubs', clubs);


//Set port
const port = process.env.PORT || 3000;

//Set up server
app.listen(port, () => {
  console.log(`Server started on port ${port}`);
});

clubs.js

const express = require("express");
const router = express.Router();
const connectionPool = require('../config/database');

//Get clubs
router.get("/search", (req, res) => {
  //Get connection from connection pool
  connectionPool.getConnection((err, dbConnection) =>{
    if(err){
      console.log(err);
    } else{
      let sql = 'Select * FROM clubs';

      let query = dbConnection.query(sql, (err, clubs)=> {
        if(err) console.log(err);
        console.log(clubs);
        //res.status(200).send(clubs);
        res.json(clubs);
      });

      //release connection back to pool
      dbConnection.release();
    }
  });
});

module.exports = router;

The request is received on the server side and and code executed. I see the array of club objects that are logged on the server side console prior to the response being sent. However, on the client side response is undefined (as seen when I debug) The line "Response has been received" that I log on client side is never output.

I have followed this same method for four other calls to the server and have had no issue. I cannot see where I am going wrong in this instance. Can you please help in identifying the issue?

Update service method as below

//Get Clubs
    getClubs(): Observable<Clubs[]> {
       return this.httpClient.get<Clubs[]>(this.localHost + "/clubs/search").map(response => response.json());    
    }

In your service side clubs.js, you're missing a return before res.json(clubs). That's why it's not returning any value.

EDIT: Or better yet use the new res.status(200).send(clubs) instead.

I found the issue. It had nothing to do with the Http Response. I checked the Network in Chrome and saw that the response was received by the browser. I used the Augury extension (For Angular) and saw that the router was in fact routing back to the SearchSportsComponent rather than to the SearchClubsComponent.

I reordered the sequence as outlined below and that resolved the issue. I need to further my understanding of routing to understanding why this is. Hopefully this will be of someone else in the future.

Code changes noted below:

app-routing.module.ts

    const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'club-category/search', component: SearchByClubsComponent },
  { path: 'club-category/search/:county_id', component: SearchByClubsComponent },
  { path: 'counties/search', component: SearchByCountiesComponent },
  { path: 'clubs/search', component: SearchClubsComponent },
  { path: ':slug/search', component: SearchSportsComponent },
  { path: ':slug/search/:countyID', component: SearchSportsComponent },  
  { path: 'club/:id', component: ClubsComponent }
]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM