У меня очень странная проблема с маршрутизацией Angular 2, где мой ngOnInit
в компоненте, к которому я перенаправляюсь, вызывается дважды, а маршрут в браузере сбрасывается до исходного маршрута.
У меня есть NotificationListComponent
и NotificationEditComponent
в MaintenanceModule
.
В моем корневом каталоге 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
, который указывает на мой NotificationEditComponent
.
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
, и я вижу все свои уведомления в списке. Для каждого уведомления в списке есть значок редактирования, событие click
которого привязано к методу edit(id: number)
в моем NotificationListComponent
notification-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;
}
}
notification-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>
Как видите, метод edit(id: number)
должен перейти к маршруту /maintenance/edit/:id
. Когда я щелкаю значок, чтобы перейти к этому маршруту, браузер мигает правильным маршрутом в адресной строке (например, localhost:4200/#/maintenance/edit/2
), но затем маршрут в адресной строке сразу же меняется обратно на localhost:4200/#/maintenance/list
. Несмотря на то, что маршрут вернулся к /maintenance/list
в адресной строке, мой NotificationEditComponent
все еще виден в реальном приложении. Однако я вижу, что метод ngOnInit
вызывается дважды в моем NotificationEditComponent
, потому что id
дважды регистрируется в консоли, и если я ставлю точку останова в функцию ngOnInit
, она дважды попадает в эту точку останова.
notification-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
);
}
}
Это, по-видимому, также вызывает другие проблемы, потому что при попытке связать значения input
со значениями в моем NotificationEditComponent
, используя, например, [(ngModel)]="notification.notificationId"
, значение не отображается на экране, хотя я также вижу с расширением Chrome Augury как запись объекта на консоль, что значение заполняется в компоненте.
notification-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
с расширением Chrome Augury. Но данные не отображаются в шаблоне, а маршрут в URL-адресе возвращается к /maintenance/list
, хотя шаблон для маршрута /maintenance/edit/:id
все еще отображается.
Обновление 2:
Как предложил @user3249448, я добавил следующее в свой AppComponent
для некоторой отладки:
constructor(private _router: Router) {
this._router.events.pairwise().subscribe((event) => {
console.log(event);
});
}
Вот вывод этого, когда я нажимаю на одну из ссылок «редактировать»:
@angular/router
версию 3.4.8. И проблема все еще возникает, даже без подстановочного маршрута. - person Andrew Mairose   schedule 09.03.2017