Angular2路由问题和ngOnInit调用了两次

时间:2017-03-09 16:08:12

标签: angular routing ngoninit

我有一个非常奇怪的问题,Angular 2路由到我路由到的组件中的ngOnInit被调用两次,并且浏览器中的路由被重置为原始路由。

我在NotificationListComponent中有NotificationEditComponentMaintenanceModule

在我的根AppModule中,我设置RouterModule将任何未映射的路由重定向到/maintenance/list

app.module.ts

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpModule,
    RouterModule.forRoot([
      {path: "", redirectTo: "maintenance/list", pathMatch: "full"},
      {path: "**", redirectTo: "maintenance/list", pathMatch: "full"}
    ], {useHash: true}),
    CoreModule.forRoot({notificationUrl: "http://localhost:8080/notification-service/notifications"}),
    MaintenanceModule
  ],
  providers: [NotificationService],
  bootstrap: [AppComponent]
})
export class AppModule { }

我在/maintenance/list中定义了MaintenanceModule路由,该路由指向我的NotificationListComponent,以及指向我/maintenance/edit/:id的{​​{1}}路由}。

maintenance.module.ts

NotificationEditComponent

当我的应用程序加载时,它正确地遵循@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事件与click

中的edit(id: number)方法绑定

通知-list.component.ts

NotificationListComponent

通知-list.component.html

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

如您所见,<div class="row"> <h1>Notification Maintenance</h1> <div *ngIf="errorMessage" class="alert-box alert"> <span>{{errorMessage}}</span> <a class="right" (click)="clearError()">&times;</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> 方法应该导航到edit(id: number)路线。当我单击图标导航到该路线时,浏览器会在地址栏中闪烁正确的路线(例如/maintenance/edit/:id),但地址栏中的路线会立即变回localhost:4200/#/maintenance/edit/2。即使路由返回到地址栏中的localhost:4200/#/maintenance/list,我的/maintenance/list仍然可以在实际应用中看到。但是,我可以看到NotificationEditComponent方法在我的ngOnInit中被调用了两次,因为NotificationEditComponent被记录到控制台两次,如果我在{{1}中放置一个断点函数,它会两次击中该断点。

通知-edit.component.ts

id

这似乎也会导致其他问题,因为在尝试将ngOnInit值绑定到@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 ); } } 中的值时使用,例如input,该值不会显示在屏幕,即使我可以看到Augury chrome扩展,以及将对象记录到控制台,该值将填充在组件中。

通知-edit.component.html

NotificationEditComponent

有谁知道为什么会发生这种情况?

更新

我删除了对[(ngModel)]="notification.notificationId"的调用,并用一些模拟数据替换它们,然后路由开始工作了!但是一旦我添加了对我的服务的调用,我就会遇到上面描述的相同问题。我甚至删除了<div class="row"> <h1>Notification Maintenance</h1> <div *ngIf="errorMessage" class="alert-box alert"> <span>{{errorMessage}}</span> <a class="right" (click)="clearError()">&times;</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,每当我使用实际服务而不是模拟数据时,仍会遇到相同的问题。

notification.service.ts

CoreModule

服务似乎运行良好 - 我可以看到端点成功返回数据,当我用Augury chrome扩展查看我的MaintenanceModule时,我可以看到数据看起来正确。但数据未显示在模板中,并且即使仍显示@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

更新2:

根据@ user3249448的建议,我将以下内容添加到/maintenance/list进行调试:

/maintenance/edit/:id

当我点击其中一个&#34;编辑&#34;链接:

Route logging

2 个答案:

答案 0 :(得分:5)

从@ user3249448获得调试帮助后,终于能够解决问题了。

原来我得到了这个NavigationError,即使没有错误记录到控制台:

enter image description here

这是完整的堆栈跟踪:

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服务的调用之前呈现的,而我的模板无法正常呈现,因为notificationundefined,所以我得到了这个{{1} },这导致了所描述的行为(似乎不应该将此错误记录到控制台而不必在NavigationError中添加额外的调试代码?)。

要解决此问题,我所要做的只是向AppComponent添加一个*ngIf,其中包含有关fieldset的所有信息。

notification

现在,一旦从Web服务返回数据,我的模板就会正确加载。

答案 1 :(得分:0)

我的猜测是,您的浏览器会将您的编辑链接解释为实际链接,而不是按照您希望的方式执行操作。这是基于您看到闪光灯的事实 - 听起来像浏览器正在尝试访问相关链接。

尝试更改您在通知列表中单击的项目,以编辑从锚标记到简单范围或div的通知。如果你没有获得闪光灯,那么你知道这是你的问题。