我有一个有角度的应用程序,该应用程序的页面包含机舱,当您单击机舱时,它应该带您进入机舱详细信息页面。当我使用json服务器数据库进行测试时,此方法运行良好,但是当我创建并将其连接到我的Express服务器时,尝试导航到我的cabdetail页面时出现错误。
我是angular和nodejs的新手,所以我对此有点迷茫。
这是错误。
错误错误:未捕获(承诺):错误:无法匹配任何路由。网址段:“ cabindetail” 错误:无法匹配任何路线。网址段:“ cabindetail” 在ApplyRedirects.push ../ node_modules/@angular/router/fesm5/router.js.ApplyRedirects.noMatchError(router.js:2469) 在CatchSubscriber.selector(router.js:2450) 在CatchSubscriber.push ../ node_modules / rxjs / _esm5 / internal / operators / catchError.js.CatchSubscriber.error(catchError.js:34) 在MapSubscriber.push ../ node_modules / rxjs / _esm5 / internal / Subscriber.js.Subscriber._error(Subscriber.js:79) 在MapSubscriber.push ../ node_modules / rxjs / _esm5 / internal / Subscriber.js.Subscriber.error中(Subscriber.js:59) 在MapSubscriber.push ../ node_modules / rxjs / _esm5 / internal / Subscriber.js.Subscriber._error(Subscriber.js:79) 在MapSubscriber.push ../ node_modules / rxjs / _esm5 / internal / Subscriber.js.Subscriber.error中(Subscriber.js:59) 在MapSubscriber.push ../ node_modules / rxjs / _esm5 / internal / Subscriber.js.Subscriber._error(Subscriber.js:79) 在MapSubscriber.push ../ node_modules / rxjs / _esm5 / internal / Subscriber.js.Subscriber.error中(Subscriber.js:59) 在TapSubscriber.push ../ node_modules / rxjs / _esm5 / internal / operators / tap.js.TapSubscriber._error(tap.js:61) 在resolvePromise(zone.js:831) 在resolvePromise(zone.js:788) 在zone.js:892 在ZoneDelegate.push ../ node_modules / zone.js / dist / zone.js.ZoneDelegate.invokeTask(zone.js:423) 在Object.onInvokeTask(core.js:17290) 在ZoneDelegate.push ../ node_modules / zone.js / dist / zone.js.ZoneDelegate.invokeTask(zone.js:422) 在Zone.push ../ node_modules / zone.js / dist / zone.js.Zone.runTask(zone.js:195) 在排水微任务队列(zone.js:601) 在ZoneTask.push ../ node_modules / zone.js / dist / zone.js.ZoneTask.invokeTask上[作为调用](zone.js:502) 在invokeTask(zone.js:1744) defaultErrorLogger @ core.js:15724
这是我的cabRouter.js
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const authenticate = require('../authenticate');
const cors = require('./cors');
const Cabins = require('../models/cabins');
const cabinRouter = express.Router();
cabinRouter.use(bodyParser.json());
cabinRouter.route('/')
.options(cors.corsWithOptions, (req,res) => {res.sendStatus(200); })
.get(cors.cors, (req, res, next) => {
Cabins.find(req.query)
.populate('comments.author')
.then((cabin) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(cabin);
}, (err) => next(err))
.catch((err) => next(err));
})
.post(cors.corsWithOptions, /*authenticate.verifyUser, authenticate.verifyAdmin,*/ (req, res, next) => {
Cabins.create(req.body)
.then((cabin) => {
console.log('Cabin Created', cabin);
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(cabin);
}, (err) => next(err))
.catch((err) => next(err));
})
.put(cors.corsWithOptions, authenticate.verifyUser,authenticate.verifyAdmin, (req, res, next) => {
res.statusCode = 403;
res.end('PUT operation not supported on /cabins');
})
.delete(cors.corsWithOptions, /*authenticate.verifyUser, authenticate.verifyAdmin,*/ (req, res, next) => {
Cabins.remove({})
.then((resp) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(resp);
}, (err) => next(err))
.catch((err) => next(err));
});
cabinRouter.route('/:cabinId')
.options(cors.corsWithOptions, (req,res) => {res.sendStatus(200); })
.get(cors.cors, (req, res, next) => {
Cabins.findById(req.params.cabinId)
.populate('comments.author')
.then((cabin) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(cabin);
}, (err) => next(err))
.catch((err) => next(err));
})
.post(cors.corsWithOptions,/*authenticate.verifyUser, authenticate.verifyAdmin,*/ (req, res, next) => {
res.statusCode = 403;
res.end('POST operation not supported on /cabins/' + req.params.cabinId);
})
.put(cors.corsWithOptions, /*authenticate.verifyUser, authenticate.verifyAdmin,*/ (req, res, next) => {
Cabins.findByIdAndUpdate(req.params.cabinId, {
$set: req.body
}, {new: true})
.then((cabin) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(cabin);
}, (err) => next(err))
.catch((err) => next(err));
})
.delete(cors.corsWithOptions, /*authenticate.verifyUser, authenticate.verifyAdmin,*/ (req, res, next) => {
Cabins.findByIdAndRemove(req.params.cabinId)
.then((resp) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json(resp);
}, (err) => next(err))
.catch((err) => next(err));
});
module.exports = cabinRouter;
这是我的app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from '../home/home.component';
import { CabinsComponent } from '../cabins/cabins.component';
import { HousesComponent } from '../houses/houses.component';
import { EcoactivitiesComponent } from '../ecoactivities/ecoactivities.component';
import { ContactComponent } from '../contact/contact.component';
import { CabinDetailComponent } from '../cabin-detail/cabin-detail.component';
import { HouseDetailComponent } from '../house-detail/house-detail.component';
const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'cabin', component: CabinsComponent },
{ path: 'house', component: HousesComponent },
{ path: 'cabindetail/:id', component: CabinDetailComponent },
{ path: 'housedetail/:id', component: HouseDetailComponent },
{ path: 'ecoactivity', component: EcoactivitiesComponent },
{ path: 'contact', component: ContactComponent },
];
@NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {}
这些是我完整项目的位桶链接。 角度
https://bitbucket.org/natashanodine/vilcabambahotel-angular/src/master/
节点快递服务器
https://bitbucket.org/natashanodine/vilcabamba-hotel-server/src/master/
这是我的机舱服务
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, map, tap, flatMap } from 'rxjs/operators';
import { Cabin } from '../shared/cabin';
import { Comment } from '../shared/comment';
import { MessageService } from './message.service';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
@Injectable({
providedIn: 'root'
})
export class CabinService {
private cabinsUrl = 'http://localhost:3000/cabins'; // URL to web api
constructor(
private http: HttpClient,
private messageService: MessageService) { }
/** GET cabins from the server */
getCabins(): Observable<Cabin[]> {
return this.http.get<Cabin[]>(this.cabinsUrl)
.pipe(
tap(cabins => this.log('fetched cabins')),
catchError(this.handleError('getCabins', []))
);
}
getFeaturedCabin(): Observable<Cabin[]> {
const url = 'http://localhost:3000/cabins?featured=true';
return this.http.get<Cabin[]>(url).pipe(
tap(_ => this.log('o')),
catchError(this.handleError<Cabin[]>(`getFeaturedCabin`))
);
}
/** GET cabin by id. Return `undefined` when id not found */
getCabinNo404<Data>(id: string): Observable<Cabin> {
const url = `${this.cabinsUrl}/?id=${id}`;
return this.http.get<Cabin[]>(url)
.pipe(
map(cabins => cabins[0]), // returns a {0|1} element array
tap(h => {
const outcome = h ? `fetched` : `did not find`;
this.log(`${outcome} cabin id=${id}`);
}),
catchError(this.handleError<Cabin>(`getCabin id=${id}`))
);
}
/** GET cabin by id. Will 404 if id not found */
getCabin(id: string): Observable<Cabin> {
const url = `${this.cabinsUrl}/${id}`;
return this.http.get<Cabin>(url).pipe(
tap(_ => this.log(`fetched cabin id=${id}`)),
catchError(this.handleError<Cabin>(`getCabin id=${id}`))
);
}
updatePosts(id, newcomment) {
const comment: Comment = newcomment;
return this.http.get<Cabin>('http://localhost:3000/cabins/' + id).pipe(
map(cabin => {
return {
id: cabin._id,
name: cabin.name,
image: cabin.image,
description: cabin.description,
priceweek: cabin.priceweek,
pricemonth: cabin.pricemonth,
featured: cabin.featured,
comments: cabin.comments
};
}),
flatMap((updatedCabin) => {
updatedCabin.comments.push(comment);
return this.http.put(this.cabinsUrl + '/' + id, updatedCabin);
})
);
}
/**
* Handle Http operation that failed.
* Let the app continue.
* @param operation - name of the operation that failed
* @param result - optional value to return as the observable result
*/
private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
// TODO: send the error to remote logging infrastructure
console.error(error); // log to console instead
// TODO: better job of transforming error for user consumption
this.log(`${operation} failed: ${error.message}`);
// Let the app keep running by returning an empty result.
return of(result as T);
};
}
/** Log a CabinService message with the MessageService */
private log(message: string) {
this.messageService.add(`CabinService: ${message}`);
}
}
我的cab-detail.component
import { Location } from '@angular/common';
import { Component, Inject, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Params, ActivatedRoute } from '@angular/router';
import { Comment } from '../shared/comment';
import { Cabin } from '../shared/cabin';
import { CabinService } from '../services/cabin.service';
@Component({
selector: 'app-cabin-detail',
templateUrl: './cabin-detail.component.html',
styleUrls: ['./cabin-detail.component.css']
})
export class CabinDetailComponent implements OnInit {
cabin: Cabin;
cabins: Cabin[];
comment: Comment;
commentForm: FormGroup;
errMess: string;
formErrors = {
'author' : '',
'rating' : '',
'comment' : ''
};
validationMessages = {
'author' : {
'required' : 'Name is required',
'minlength' : 'Name must be at least 2 characters long',
'maxlength' : 'Name cannot be more that 25 characters long'
}
};
constructor(
private cabinService: CabinService,
private fb: FormBuilder,
private location: Location,
private route: ActivatedRoute,
@Inject("BaseURL") private BaseURL
) {
this.createForm();
}
ngOnInit(): void {
this.getCabin();
this.getCabins();
}
getCabin(): void {
const id = +this.route.snapshot.paramMap.get('id');
this.cabinService.getCabin(id)
.subscribe(cabin => this.cabin = cabin);
}
getCabins(): void {
this.cabinService.getCabins()
.subscribe(cabins => this.cabins = cabins);
}
/* addComment(description: string): void {
description = description.trim();
if (!description) { return; }
this.cabinService.addCabin({ description } as Cabin)
.subscribe(cabin => {
this.cabins.push(cabin);
});
}
*/
/* delete(cabin: Cabin): void {
this.cabins = this.cabins.filter(h => h !== cabin);
this.cabinService.deleteCabin(cabin).subscribe();
}
*/
createForm() {
this.commentForm = this.fb.group({
author: ['', [ Validators.required, Validators.minLength(2) ] ],
rating: 5,
comment: ['', [ Validators.required ] ],
});
this.commentForm.valueChanges
.subscribe(data => this.onValueChanged(data));
this.onValueChanged(); // (re)set form validation messages
}
onValueChanged(commentFormData?: any) {
if (!this.commentForm) {
return;
}
const form = this.commentForm;
for (const field in this.formErrors) {
this.formErrors[field] = '';
const control = form.get(field);
if (control && control.dirty && !control.valid) {
const messages = this.validationMessages[field];
for (const key in control.errors) {
this.formErrors[field] += messages[key] + ' ';
}
}
}
if (this.commentForm.valid) {
this.comment = this.commentForm.value;
} else {
this.comment = undefined;
}
}
onSubmit() {
const id = +this.route.snapshot.paramMap.get('id');
this.comment['date'] = new Date().toISOString();
this.cabin.comments.push(this.comment);
this.cabinService.updatePosts(this.cabin._id, this.comment).subscribe(() => {
console.log("PUT is done");
})
this.commentForm.reset({
author: '',
rating: 5,
comment: ''
});
}
}
答案 0 :(得分:0)
正如我所看到的,Angular抛出了一个路由器错误,在路由表中找不到cabdetail。
当我检查了您提供的代码时,我发现路由器表在路由中需要一个参数:id,因此,当您连接到JSON服务器时(并且数据很好,模型中的ID被填充,并且该路线例如以Cabertail / 5出现。
似乎发生了什么事,当您连接快递服务器时,没有在模型中填充id属性,这使得路由/ cabindetail /无效,并且根据路由表无效(因为ID为未定义,而不是0)。
您需要做的是检查来自服务器的JSON,并确保正确填充了ID。