我在MaintenanceModule中有一个NotificationListComponent和一个NotificationEditComponent.
在我的根AppModule中,我设置RouterModule将任何未映射的路由重定向到/ maintenance / list.
app.module.ts:
@NgModule({ declarations: [ AppComponent ],imports: [ browserModule,HttpModule,RouterModule.forRoot([ {path: "",redirectTo: "maintenance/list",pathMatch: "full"},{path: "**",pathMatch: "full"} ],{useHash: true}),CoreModule.forRoot({notificationUrl: "http://localhost:8080/notification-service/notifications"}),MaintenanceModule ],providers: [NotificationService],bootstrap: [AppComponent] }) export class AppModule { }
并且我的MaintenanceModule中定义了/ maintenance / list路由,它指向我的NotificationListComponent,以及一个指向我的NotificationEditComponent的/ maintenance / edit /:id路由.
maintenance.module.ts:
@NgModule({ imports: [ CommonModule,RouterModule.forChild([ {path: "maintenance/list",component: NotificationListComponent,pathMatch: 'full'},{path: "maintenance/edit/:id",component: NotificationEditComponent,pathMatch: 'full'} ]),FormsModule ],declarations: [ NotificationListComponent,NotificationEditComponent ] }) export class MaintenanceModule {}
当我的应用程序加载时,它正确地遵循/ maintenance / list路由,我可以在列表中看到我的所有通知.对于列表中的每个通知,都有一个编辑图标,它的点击事件绑定到我的NotificationListComponent中的edit(id:number)方法
通知-list.component.ts:
@Component({ templateUrl: 'notification-list.component.html' }) export class NotificationListComponent implements OnInit { notifications: Notification[]; errorMessage: string; constructor(private _notificationService: NotificationService,private _router: Router) {} ngOnInit(): void { this._notificationService.getNotifications() .subscribe( notifications => this.notifications = notifications,error => this.errorMessage = <any>error); } clearError(): void { this.errorMessage = null; } }
通知-list.component.html:
<div class="row"> <h1>Notification Maintenance</h1> <div *ngIf="errorMessage" class="alert-Box alert"> <span>{{errorMessage}}</span> <a class="right" (click)="clearError()">×</a> </div> <p-dataTable [value]="notifications" [sortField]="'code'" [responsive]="true" [sortOrder]="1" [rows]="10" [paginator]="true" [rowsPerPageOptions]="[10,50,100]"> <p-header>Available Notifications</p-header> <p-column [field]="'code'" [header]="'Code'" [sortable]="true" [style]="{'width':'10%'}"></p-column> <p-column [field]="'name'" [header]="'Name'" [sortable]="true" [style]="{'width':'40%'}"></p-column> <p-column [field]="'roles'" [header]="'Roles'" [style]="{'width':'40%'}"></p-column> <p-column [field]="'notificationId'" [header]="'Edit'" [style]="{'width':'10%'}"> <template let-row="rowData" pTemplate="body"> <a [routerLink]="'/maintenance/edit/' + row['notificationId']"><span class="fa fa-pencil fa-2x"></span></a> </template> </p-column> </p-dataTable> </div>
您可以看到,编辑(id:number)方法应该导航到/ maintenance / edit /:id路由.当我点击图标导航到该路由时,浏览器会在地址栏中闪烁正确的路由(例如localhost:4200 /#/ maintenance / edit / 2),但是地址栏中的路由会立即更改为localhost: 4200 /#/维护/列表.即使路由返回到/维护/列表中的地址栏,我的NotificationEditComponent在实际的应用程序仍然可见.但是,我可以看到ngOnInit方法在我的NotificationEditComponent中被调用了两次,因为该id被记录到控制台两次,如果我在ngOnInit函数中放置了一个断点,它会将该断点点击两次.
通知-edit.component.ts:
@Component({ templateUrl: "notification-edit.component.html" }) export class NotificationEditComponent implements OnInit{ notification: Notification; errorMessage: string; constructor(private _notificationService: NotificationService,private _route: ActivatedRoute,private _router: Router) { } ngOnInit(): void { let id = +this._route.snapshot.params['id']; console.log(id); this._notificationService.getNotification(id) .subscribe( notification => this.notification = notification,error => this.errorMessage = <any>error ); } }
这似乎也是导致其他问题,因为当尝试使用例如[(ngModel)] =“notification.notificationId”将输入值绑定到NotificationEditComponent中的值时,该值不会显示在屏幕上,即使我可以使用Augury chrome扩展名,以及将对象记录到控制台,该值将填充到组件中.
通知-edit.component.html:
<div class="row"> <h1>Notification Maintenance</h1> <div *ngIf="errorMessage" class="alert-Box alert"> <span>{{errorMessage}}</span> <a class="right" (click)="clearError()">×</a> </div> <p-fieldset [legend]="'Edit Notification'"> <label for="notificationId">ID: <input id="notificationId" type="number" disabled [(ngModel)]="notification.notificationId"/> </label> </p-fieldset> </div>
有没有人知道为什么会发生这种情况?
更新:
我删除了对NotificationService的调用,并将其替换为只是一些模拟数据,然后路由开始工作!但是,一旦我添加了对我的服务的电话,我得到了上面我描述的相同的问题.我甚至删除了CoreModule,只是将该服务直接添加到我的MaintenanceModule中,并且每当我使用实际的服务而不是只是模拟数据时,仍然会遇到同样的问题.
notification.service.ts:
@Injectable() export class NotificationService { private _notificationUrl : string = environment.servicePath; constructor(private _http: Http) { } getNotifications(): Observable<Notification[]> { return this._http.get(this._notificationUrl) .map((response: Response) => <Notification[]>response.json()) .catch(this.handleGetError); } getNotification(id: number): Observable<Notification> { return this._http.get(this._notificationUrl + "/" + id) .map((response: Response) => <Notification>response.json()) .catch(this.handleGetError); } postNotification(notification: Notification): Observable<number> { let id = notification.notificationId; let requestUrl = this._notificationUrl + (id ? "/" + id : ""); return this._http.post(requestUrl,notification) .map((response: Response) => <number>response.json()) .catch(this.handlePostError); } private handleGetError(error: Response) { console.error(error); return Observable.throw('Error retrieving existing notification(s)!'); } private handlePostError(error: Response) { console.error(error); return Observable.throw('Error while attempting to save notification!'); } }
而且服务似乎运行正常 – 我可以看到端点成功返回数据,当我看到我的NotificationEditComponent与Augury铬扩展时,我可以看到数据看起来正确.但是,模板中不会显示数据,并且仍然显示/ maintenance / edit /:id路由的模板,URL中的路由返回到/ maintenance / list.
更新2:
根据@ user3249448的建议,我将以下内容添加到我的AppComponent进行一些调试:
constructor(private _router: Router) { this._router.events.pairwise().subscribe((event) => { console.log(event); }); }
原来我得到这个NavigationError,即使没有错误记录到控制台:
这是完整的堆栈跟踪:
TypeError: Cannot read property 'notificationId' of undefined at CompiledTemplate.proxyViewClass.View_NotificationEditComponent0.detectChangesInternal (/MaintenanceModule/NotificationEditComponent/component.ngfactory.js:487:49) at CompiledTemplate.proxyViewClass.AppView.detectChanges (http://localhost:4200/vendor.bundle.js:80125:14) at CompiledTemplate.proxyViewClass.DebugAppView.detectChanges (http://localhost:4200/vendor.bundle.js:80320:44) at CompiledTemplate.proxyViewClass.AppView.internalDetectChanges (http://localhost:4200/vendor.bundle.js:80110:18) at CompiledTemplate.proxyViewClass.View_NotificationEditComponent_Host0.detectChangesInternal (/MaintenanceModule/NotificationEditComponent/host.ngfactory.js:29:19) at CompiledTemplate.proxyViewClass.AppView.detectChanges (http://localhost:4200/vendor.bundle.js:80125:14) at CompiledTemplate.proxyViewClass.DebugAppView.detectChanges (http://localhost:4200/vendor.bundle.js:80320:44) at ViewRef_.detectChanges (http://localhost:4200/vendor.bundle.js:60319:20) at RouterOutlet.activate (http://localhost:4200/vendor.bundle.js:65886:42) at ActivateRoutes.placeComponentIntoOutlet (http://localhost:4200/vendor.bundle.js:24246:16) at ActivateRoutes.activateRoutes (http://localhost:4200/vendor.bundle.js:24213:26) at http://localhost:4200/vendor.bundle.js:24149:58 at Array.forEach (native) at ActivateRoutes.activateChildRoutes (http://localhost:4200/vendor.bundle.js:24149:29) at ActivateRoutes.activate (http://localhost:4200/vendor.bundle.js:24123:14)
所以本质上,我的模板正在渲染之前,我的Web服务的调用被返回,并且我的模板无法正确呈现,因为通知是未定义的,所以我得到这个导航错误,导致描述的行为(这不像这样错误应该记录到控制台,而不必在AppComponent中添加额外的调试代码?).
要解决这个问题,我只需要添加一个* ngIf到我的字段集,其中包含有关通知的所有信息.
<p-fieldset [legend]="'Edit Notification'" *ngIf="notification">
一旦数据从Web服务返回,现在我的模板正确加载.