How to store, access and retrieve Image files from Nodejs-Express ( MongoDB ) to Angular8 FrontEnd, - node.js

This is an Employee Management System, Profile images of Employees are uploaded and stored in API server (defined path).
I implemented the following steps.
Step 1: API server Request - the sample API code
router.get('/public/users-images/*', function(req, res) {
var filepath = __dirname +'/..'+req.url
fs.exists(filepath, (exists) => {
if (exists) {
var filepath = filepath
} else {
var filepath = __dirname +'/../public/users-images/user-image.png'
}
})
var fileext = filepath.split('.')
fs.readFile(filepath, function(err, buffer){
// console.log(base64Image);
var base64Image = new Buffer(buffer, 'binary').toString('base64');
res.send({img:'data:image/'+fileext[fileext.length -1]+';base64,' + base64Image});
});
})
Step 2: Front end request from Angular8 using the pipe method,
import { Pipe, PipeTransform } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Pipe({
name: 'userImages'
})
export class UserImagesPipe implements PipeTransform {
constructor(
private http: HttpClient,
private authenticationService: AuthenticationService
) { }
transform(img_name: string): any {
this.http.get('/public/users-images/'+img_name).subscribe(result => {
// You could also cache your result
return result.img;
});
}
}
Now, My question is , How to access the images from API Server location and display it in the UI screen. I assume to use the below method.
Html template <img [src]="'user-image.png' | userImages" class="responsive-12">
I use PIPE method - Because the User List (User Information including the Profile images ) will be used in Search filter, Task Creation form etc., So I tried to implement it in common, And maybe In the future, there is a chance to implement it through CDN.
Am I doing it in the right way? Or will there be any vents for issues ?

You are overcomplicating it. Let the browser do the fetching of the image.
Simply output the correct path to the image in the view
<img [src]="'/public/users-images/' + username + '.png'" alt="" />
or if you want you could create a pipe for it, but only to output the correct path
import { Pipe, PipeTransform } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Pipe({
name: 'userImages'
})
export class UserImagesPipe implements PipeTransform {
constructor(
private authenticationService: AuthenticationService
) { }
transform(img_name: string): any {
return `/public/users-images/${img_name}.png`
}
}
<img [src]="username | userImages" alt="" />

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

How to pass the data from one component to another component using angular5

I am creating test application using angular so in that i need to display user details while i click on edit button then, that user details will need to display in another component.i have written query to get user details while clicking edit button, but unable to get data so what is the exact procedure for changes need to be done in query.
This is my manageusers.component.html
<tr *ngFor="let detail of userDetails" style="text-align:center">
<td><input type="checkbox"></td>
<td>{{detail.username}}</td>
<td>{{detail.uemail}}</td>
<td>Inactive</td>
<td>{{detail.added_on}}</td>
<td>
<a routerLink="/dashboard-info/basic-settings">
<i class="fas fa-edit" (click)="editIssue(i,detail._id)"></i>
</a>
This is my manageusers.component.ts
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup , Validators } from '#angular/forms';
import { DataService } from '../../../services/data.service';
import { AccountService } from '../../../services/account.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-manage-users',
templateUrl: './manage-users.component.html',
styleUrls: ['./manage-users.component.css'],
})
export class ManageUsersComponent implements OnInit {
userDetails:any = [];
detail:Detail={
added_on:'',
username:'',
uemail:'',
upassword:'',
};
constructor(private router: Router,private fb:FormBuilder,private dataService: DataService, private accountService: AccountService) {}
editIssue(id,detail){
alert(detail);
let data = {
_id:detail,
};
this.accountService.editDetail(data).subscribe(
response => {
console.log(response);
this.userDetails = JSON.parse(response);
//this.router.navigate(['/dashboard-info/basic-settings', this.userDetails]);
},
err => {
console.error('User Not found');
})
}
ngOnInit() {}
}
interface Detail{
added_on:string
username:string,
upassword:string,
uemail:string,
}
accountService.ts
editDetail(data) {//Getting User with userId
return this.http.post(this.apiPath + 'user/editDetail', data,{responseType: 'text'});
}
usercontroller.js
userRouter.post('/editDetail', function (req, res) {
console.log(req.body._id);
Collections.user.findOne({_id: req.body._id}, function (err, result) {
if (err) return res.status(500).send("There was a problem finding the user");
if (result) {
console.log(result);
res.status(200).send(result);
} else {
return res.status(500).send("User Not Found with Details: " + JSON.stringify(user));
}
});
});
I think it would be better to set the User you want to show in the component as input, get the User you need in an http call and pass it to the component afterwards by it's input. See more for component input here: https://toddmotto.com/passing-data-angular-2-components-input
To retrieve data by http call you should use Angulars Http Client, which is really easy to use and saves you from using plain javascript. See here: https://blog.angular-university.io/angular-http/

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

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>

Resources