My table list of tours displays all the required info except that of image Cover. I cannot figure out why the image path is broken. I suspected my back-end code that serves my static files but as far as I can tell all appears to be fine.
In back-end code I have the following line of code for serving static files on my app.js file.
app.use(
'/public/img/countries',
express.static(`${__dirname}/public/img/countries`)
);
app.use('/public/img/tours', express.static(`${__dirname}/public/img/tours`));
app.use('/public/img/users', express.static(`${__dirname}/public/img/users`));
On my tour handler function, tourController.js back-end code I have the below code as it specifically pertains to images.
const multerStorage = multer.memoryStorage();
const multerFilter = (req, file, cb) => {
if (file.mimetype.startsWith('image')) {
cb(null, true);
} else {
cb(new AppError('Not an image! Please upload only images.', 400), false);
}
};
const upload = multer({
storage: multerStorage,
fileFilter: multerFilter
// limits: { fileSize: maxSize }
});
exports.uploadTourImages = upload.fields([
//req.files for fields
{ name: 'imageCover', maxCount: 1 },
{ name: 'images', maxCount: 3 }
]);
exports.resizeTourImages = catchAsync(async (req, res, next) => {
if (!req.files.imageCover || !req.files.images) return next();
// 1) Cover image
req.body.imageCover = `tour-${req.params.id}-${Date.now()}-cover.jpeg`;
await sharp(req.files.imageCover[0].buffer)
.rotate()
.resize(1903, 1268)
.toFormat('jpeg')
.jpeg({ quality: 90 })
.toFile(`public/img/tours/${req.body.imageCover}`);
req.body.images = [];
await Promise.all(
req.files.images.map(async (file, i) => {
const filename = `tour-${req.params.id}-${Date.now()}-${i 1}.jpeg`;
await sharp(file.buffer)
.rotate()
.resize(1903, 1268)
.toFormat('jpeg')
.jpeg({ quality: 90 })
.toFile(`public/img/tours/${filename}`);
req.body.images.push(filename);
})
);
next();
});
On my factory function on my back-end model
exports.getAll = Model =>
catchAsync(async (req, res, next) => {
let filter = {};
if (req.params.tourId) filter = { tour: req.params.tourId };
//EXECUTE QUERY
const features = new APIFeatures(Model.find(filter), req.query)
.filter()
.sort()
.limitFields()
.paginate();
const doc = await features.query;
//SEND REPONSE
res.status(200).json({
status: 'success',
results: doc.length,
data: {
data: doc
}
});
next();
});
On my Front-end, I have the below code for my table on my tour-list.component.html
<p-table [value]="tours" styleClass="p-datatable-gridlines" responsiveLayout="scroll">
<ng-template pTemplate="header">
<tr>
<th pSortableColumn="name">Name<p-sortIcon field="name"></p-sortIcon></th>
<th>Image Cover</th>
<th pSortableColumn="price">Price<p-sortIcon field="price"></p-sortIcon></th>
<th pSortableColumn="ratingsAverage">
Ratings Average <p-sortIcon field="ratingsAverage"></p-sortIcon>
</th>
<th pSortableColumn="country">Country<p-sortIcon field="country"></p-sortIcon></th>
<th pSortableColumn="difficulty">
Difficulty<p-sortIcon field="difficulty"></p-sortIcon>
</th>
<th pSortableColumn="availabilityDates">
Availability Dates<p-sortIcon field="availabilityDates"></p-sortIcon>
</th>
<th pSortableColumn="maxGroupPair">
Maximum Group Pairs<p-sortIcon field="maxGroupPair"></p-sortIcon>
</th>
<th pSortableColumn="minimumAge">
Minimum Age<p-sortIcon field="minimumAge"></p-sortIcon>
</th>
<th pSortableColumn="dateCreated">
Date Created<p-sortIcon field="dateCreated"></p-sortIcon>
</th>
<th></th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-tour>
<tr>
<td>{{ tour.name }}</td>
<td><img [src]="tour.imageCover" width="100px" height="67px" alt="" /></td>
<td>{{ tour.price }}</td>
<td>{{ tour.ratingsAverage }}</td>
<td>{{ tour.country.name }}</td>
<td>{{ tour.difficulty }}</td>
<td>{{ tour.availabilityDates }}</td>
<td>{{ tour.maxGroupPair }}</td>
<td>{{ tour.minimumAge }}</td>
<td>{{ tour.dateCreated | date: 'longDate' }}</td>
</tr>
</ng-template>
</p-table>
My tours-list.component.ts file has the below code
import { Component, OnInit } from '@angular/core';
import { ToursService } from '@tourafrika/tours';
@Component({
selector: 'admin-tours-list',
templateUrl: './tours-list.component.html',
styles: []
})
export class ToursListComponent implements OnInit {
tours = [];
constructor(private tourService: ToursService) {}
ngOnInit(): void {
this._getTours();
}
private _getTours() {
this.tourService.getTours().subscribe((tours) => {
this.tours = tours;
});
}
}
My Library model code on my front-end has the below code.
import { Country } from './country';
import { User } from './user';
export class Tour {
id?: string;
name?: string;
slug?: string;
country?: Country;
duration?: number;
maxGroupPair?: number;
singleSupplement?: number;
difficulty?: string;
ratingsAverage?: number;
ratingsQuantity?: number;
price?: number;
priceDiscount?: number;
overview?: string;
imageCover?: string;
images?: string[];
dateCreated?: string;
availabilityDates?: string[];
isFeatured?: boolean;
secretTour?: string;
minimumAge?: string;
departureLocation?: string;
locations?: string;
guides?: [User];
}
export interface ITourListResponse {
status: string;
results: number;
data: { data: Tour[] };
}
My services file of tours.service.ts has the below code.
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Tour, ITourListResponse } from '../models/tour';
import { map } from 'rxjs/operators';
import { environment } from '@env/environment';
@Injectable({
providedIn: 'root'
})
export class ToursService {
apiURLTours = environment.apiUrl 'tours';
constructor(private http: HttpClient) {}
getTours(): Observable<Tour[]> {
return this.http
.get<ITourListResponse>(this.apiURLTours)
.pipe(map((response: ITourListResponse) => response.data.data));
}
Thanks!
CodePudding user response:
I have solved this by completely restructuring my code on my toursController.ts file on my backend by running the below code to redefine my imageCover path. All good now!
const { file } = req;
let imagepath;
if (file) {
const fileName = req.file.filename;
const basePath = `${req.protocol}://${req.get('host')}/public/img/tours/`;
imagepath = `${basePath}${fileName}`;
} else {
imagepath = tour.imageCover;
}