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

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...");
});

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);
});
});

Related

how to prevent file upload when body validation fails in nestjs

I have the multipart form to be validated before file upload in nestjs application. the thing is that I don't want the file to be uploaded if validation of body fails.
here is how I wrote the code for.
// User controller method for create user with upload image
#Post()
#UseInterceptors(FileInterceptor('image'))
create(
#Body() userInput: CreateUserDto,
#UploadedFile(
new ParseFilePipe({
validators: [
// some validator here
]
})
) image: Express.Multer.File,
) {
return this.userService.create({ ...userInput, image: image.path });
}
Tried so many ways to turn around this issue, but didn't reach to any solution
Interceptors run before pipes do, so there's no way to make the saving of the file not happen unless you manage that yourself in your service. However, another option could be a custom exception filter that unlinks the file on error so that you don't have to worry about it post-upload
This is how I created the whole filter
import { isArray } from 'lodash';
import {
ExceptionFilter,
Catch,
ArgumentsHost,
BadRequestException,
} from '#nestjs/common';
import { Request, Response } from 'express';
import * as fs from 'fs';
#Catch(BadRequestException)
export class DeleteFileOnErrorFilter implements ExceptionFilter {
catch(exception: BadRequestException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const status = exception.getStatus();
const getFiles = (files: Express.Multer.File[] | unknown | undefined) => {
if (!files) return [];
if (isArray(files)) return files;
return Object.values(files);
};
const filePaths = getFiles(request.files);
for (const file of filePaths) {
fs.unlink(file.path, (err) => {
if (err) {
console.error(err);
return err;
}
});
}
response.status(status).json(exception.getResponse());
}
}

How can i asynchronouslycall this service function in another component? Angular 11

I have an async function getIdentByInfo and in the console i get the right output if i log it in this function. As soon as i call it in another component it doesnt work and i only get 'undefined'. I know it has something to do with beeing ssynchrone and Promises but i cant figure out how to solve my issue. I need the Model class filled with attributes coming from the http request in another component to send them to another service
import { EventEmitter, Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { IdentModel } from "../models/identmodel.model";
import { IdentteilComponent } from "../pages/identteil/identteil.component";
#Injectable({
providedIn: 'root',
})
export class InfoWebservice {
url = 'http://localhost:4201';
ident: IdentModel[];
constructor(private http: HttpClient) { }
// promise vom typ IdentModel zurückgeben
getIdentByInfo(id: string, vwk: string) {
this.http.get(this.url).toPromise().then(data => {
for (let i in data){
this.ident.push(data[i])
if ( this.ident[i].identNr == id && this.ident[i].vwk == vwk){
return this.ident[i];
}
}
});
}
}
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { InfoWebservice } from '../../webservices/info.webservice'
import { ImageWebservice } from '../../webservices/image.webservice'
import { IdentModel } from "../../models/identmodel.model";
#Component({
selector: 'app-identteil',
templateUrl: './identteil.component.html',
styleUrls: ['./identteil.component.scss']
})
export class IdentteilComponent implements OnInit {
ident = [];
identNr:string;
vwk:string;
imgFrontLink:string;
imgBackLink:string;
constructor(private router: Router, private service: InfoWebservice, private image: ImageWebservice) { }
getIdentNr() : string {
var split = this.router.url.split("/");
this.identNr = split[2];
return this.identNr;
}
//return type is STRING
getVwk() {
// output von window.location.host = repapp-maw.dbl.de
// var splitHost = window.location.host.split(".");
var splitHost = 'repapp-maw';
var splitV = splitHost.split("-");
this.vwk = splitV[1];
return this.vwk;
}
callInfoService = async () => {
return await this.service.getIdentByInfo(this.getIdentNr(), this.getVwk());
}
ngOnInit() {
console.log(this.callInfoService());
}
}
When you use angular, its always preferred not to use await/Promise. Angular has an in-built RX-JS library which has tonnes of super-awesome functionalities that you can use.
For Example, in your case, you can do something like this:
// Your Service File can make use of 'Behavior Subject'
// Please read more about it here: https://www.learnrxjs.io/learn-rxjs/subjects/behaviorsubject
import { EventEmitter, Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { IdentModel } from "../models/identmodel.model";
import { IdentteilComponent } from "../pages/identteil/identteil.component";
#Injectable({
providedIn: 'root',
})
export class InfoWebservice {
url = 'http://localhost:4201';
ident: IdentModel[];
initialIdentValues: IdentModel = [];
private identSource: BehaviorSubject<IdentModel[]> = new BehaviorSubject<IdentModel[]>(this.initialIdentValues);
public identValuesObs$: Observable<IdentModel[]> = this.identSource.asObservable();
// Create a method to set the values in component-1
setIdentValues(identValues: IdentModel[]) {
this.identSource.next(identValues);
}
// Create a method to return values in component-2 or any component
returnIdentValues() {
return this.identValuesObs$;
}
constructor(private http: HttpClient) { }
// Change your service call to this:
getIdentByInfo(id: string, vwk: string): Observable<any> {
return this.http.get(this.url);
}
}
Now in your component-1 where you want to set the values of this identvalues:
// Component-1
constructor(private infoWebService: InfoWebService){}
// Create a method where you get the values
someMethod() {
// Call the API method here and subscribe and then set the values
this.infoWebService.getIdentInfoById(id, vwk).subscribe((data: any) => {
// Your logic goes here ANDD
if (data) {
for (let i in data){
this.ident.push(data[i])
let localIdentsWithRequiredLogic = [];
if ( this.ident[i].identNr == id && this.ident[i].vwk == vwk){
localIdentsWithRequiredLogic.push(this.ident[i]);
}
// THIS IS IMPORTANT
this.infoWebService.setIdentValues(localIdentsWithRequiredLogic);
}
}
})
}
Then in component-2 or whatever component you want, you can retrieve it using the returnIdentValues method like this:
// In component-2
inSomeMethodWhereYouRequireIdentValues() {
this.infoWebService.returnIdentValues().subscribe(data => {
console.log(data) // this is data that you set in component one
})
}

I am not getting response from nodeJS server in angular 2 [duplicate]

This question already has answers here:
How do I return the response from an Observable/http/async call in angular?
(10 answers)
Closed 5 years ago.
I am newbie to MEAN stack development. So, please help me to figure out the problem.
app.js
const express = require('express');
const app = express();
const path = require('path');
app.use(express.static(path.join(__dirname, './darwin-src/public')));
const port = 3000;
app.get('/images', (req, res) => {
console.log('In server');
var data;
var Scraper = require ('images-scraper')
, google = new Scraper.Google();
google.list({
keyword: 'banana',
num: 10,
detail: true,
nightmare: {
show: false
}
})
.then(function (data) {
console.log('first 10 results from google', data);
res.end("" + data);
})
.catch(function(err) {
console.log('err', err);
});
});
app.listen(port, () => {
console.log(`Starting the server at port ${port}`);
});
image-service.service.ts
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { Image } from './model/image';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import 'rxjs/add/observable/of';
#Injectable()
export class ImageServiceService {
constructor(private http: Http) { }
private serverApi = 'http://localhost:3000';
public getImages(image: string): Observable<Image[]> {
console.log('Inside Service');
let URI = `${this.serverApi}/images`;
return this.http.get(URI)
.map(function(res) {
return res.json();
});
}
}
image-view.component.ts
import { Component, OnInit } from '#angular/core';
import { ImageServiceService } from '../image-service.service';
import { Image } from '../model/image';
#Component({
selector: 'app-image-view',
templateUrl: './image-view.component.html',
styleUrls: ['./image-view.component.css']
})
export class ImageViewComponent implements OnInit {
private data: Image[] = [];
constructor(private imageService: ImageServiceService) { }
ngOnInit() {
}
onSubmit(image: string) {
console.log(image);
this.imageService.getImages(image).subscribe(response => this.data = response);
console.log(this.data.length);
}
}
The length of array is zero and I can't figure out why. The response comes on nodejs console after a while but the frontend displays the result before the response comes. Please help!
Hit the server url separately in browser and see if you get the expected response. If this is okay, then the problem is with the client.
On seeing your client code, one issue seems obvious. You are not using the observable from ImageServiceService properly. All your manipulations should be within the subscribe method.
onSubmit(image: string) {
this.imageService.getImages(image).subscribe(response => {
this.data = response;
console.log(this.data.length);
// Do other manipulations that you wish to do
});
}
If you using the observable to display something in the view, then
consider . using async pipe
The code in the subscribe handler is not executed synchronously. So, your console.log statement is executed before you get a response from your server. I don't see your image-view.component.html markup. But, I believe you need to use the async pipe in your bound option.
private data$: Observable<Image[]>;
onSubmit(image: string) {
console.log(image);
this.data$ = this.imageService.getImages(image);
}
And you HTML:
<div *ngFor="let image of data$ | async">
{{image.value}}
</div>

Storing observable data into global variable returns 'undefined' in Angular 4

I am currently working with a node server that I've set up and created an endpoint /user-info which res.send({id: <my-id>, name: <my-display-name>})
On Angular I have created a global.service.ts file that will call this endpoint using http.get and subscribe that data and store into two variables I have declared.
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class Globals {
constructor(private http: HttpClient) { }
public id: string;
public name: string;
userInfo() {
this.http.get('/user-info').subscribe(
(data: any) => {
this.id = data.id;
}
);
console.log(this.id);
}
}
Once I console.log(this.id) it returns undefined. I have already the server-side to see if that was causing the problem but it returns a string.
In my server.js file (node server) I am working with express. This is the endpoint:
app.get('/user-info', function(req, res) {
client.get('id', (err, data) => {
client.get('name', (err, reply) => {
res.send({id: data, name: reply})
})
})
})
I am using redis to store values 'id' and 'name' and the client.get is just a redis command used to call those values from cache. I have tested just checking localhost:8000/user-info and everything looks fine.
Am I missing/misunderstanding something? Thanks!
if console.log still outside of call, it will execute before you got a response. Try this:
userInfo() {
this.http.get('/user-info').subscribe(
(data: any) => {
this.id = data.id
console.log(this.id);
}
)
}

Angular2 - Handling API Response

Good afternoon! I'm new in Angular 2, so I'm sorry in advance if my question is generic. I cannot figure out how to handle an API response.
My NodeJS Server API function is (Checked and works fine):
router.get('/appointment/:iatreio/:time', function(req, res, next) {
var paramIatreio = req.params.iatreio;
var paramTime = req.params.time;
db.appointments.findOne({iatreio: paramIatreio, time: req.params.time}, function(err, resultFound) {
if (err) { res.send(err); }
if (resultFound) {
res.json(true); // 1st Question: For best practice, res.json(true) or res.send(true)?
} else {
res.json(false);
}
});
});
My Angular2 Service:
import { Injectable } from '#angular/core';
import { Headers , Http } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Injectable()
export class AppointmentService {
constructor(private http: Http) { }
isBooked(iatreio: string, time: string): Observable<boolean> {
return this.http
.get('http://localhost:3000/appointment/'+iatreio+'/'+time)
.map(); //2nd Question: What inside map()?
}
} // end of Service
Component Function
isBooked(selectedIatreio: string, selectedTime: string): boolean {
this.appointmentService
.isBooked(selectedIatreio, selectedTime)
.subscribe(() => {}); //3rd Question: What inside subscribe()?
}
My final goal is the "isBooked(...)" function of my Component to be called and to return true or false. I have seen the code in the examples in the Angular2 site, but I'm a little confused on my case.
Can Service function return directly a true or false value or it has to be an Observable?? Map() function is necessary??
Generally, my thinking is right?? Or my goal can be accomplished more easily??
Thank you a lot for your time!!
map is used to convert the response into the model which you look for
isBooked(iatreio: string, time: string): Observable<boolean> {
return this.http
.get('http://localhost:3000/appointment/'+iatreio+'/'+time)
.map((response)=><boolean>response.json());
}
subscribe will return the data emitted by the service
isBooked(selectedIatreio: string, selectedTime: string): boolean {
this.appointmentService
.isBooked(selectedIatreio, selectedTime)
.subscribe((data) => {
//your operation
console.log(data);
});
}

Resources